2017-02-16 15:52:27 +00:00
|
|
|
// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
|
2016-11-24 14:29:43 +00:00
|
|
|
//
|
2017-02-16 15:52:27 +00:00
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
use std::cmp;
|
2017-01-13 10:52:41 +00:00
|
|
|
use std::io::{Write, Cursor};
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
use nom;
|
|
|
|
use nom::IResult;
|
|
|
|
|
|
|
|
use flavors::parser as flavors;
|
|
|
|
|
2016-12-23 17:04:32 +00:00
|
|
|
use gst_plugin::error::*;
|
|
|
|
use gst_plugin::demuxer::*;
|
|
|
|
use gst_plugin::buffer::*;
|
|
|
|
use gst_plugin::adapter::*;
|
|
|
|
use gst_plugin::utils;
|
2016-12-25 11:16:12 +00:00
|
|
|
use gst_plugin::utils::Element;
|
|
|
|
use gst_plugin::log::*;
|
2016-12-30 11:11:30 +00:00
|
|
|
use gst_plugin::caps::Caps;
|
2017-02-03 14:34:17 +00:00
|
|
|
use gst_plugin::miniobject::*;
|
2017-01-15 19:56:20 +00:00
|
|
|
use gst_plugin::value::Rational32;
|
2017-01-13 10:52:41 +00:00
|
|
|
use gst_plugin::bytes::*;
|
2016-12-25 11:16:12 +00:00
|
|
|
|
2017-04-12 13:44:34 +00:00
|
|
|
use slog::Logger;
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
const AUDIO_STREAM_ID: u32 = 0;
|
|
|
|
const VIDEO_STREAM_ID: u32 = 1;
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2016-12-03 22:57:42 +00:00
|
|
|
enum State {
|
|
|
|
Stopped,
|
2016-11-24 14:29:43 +00:00
|
|
|
NeedHeader,
|
2016-12-04 10:58:59 +00:00
|
|
|
Skipping {
|
|
|
|
audio: bool,
|
|
|
|
video: bool,
|
|
|
|
skip_left: u32,
|
|
|
|
},
|
2016-12-03 22:57:42 +00:00
|
|
|
Streaming,
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2016-12-03 22:57:42 +00:00
|
|
|
struct StreamingState {
|
2016-12-04 10:58:59 +00:00
|
|
|
audio: Option<AudioFormat>,
|
|
|
|
expect_audio: bool,
|
|
|
|
video: Option<VideoFormat>,
|
|
|
|
expect_video: bool,
|
2016-11-24 14:29:43 +00:00
|
|
|
got_all_streams: bool,
|
2016-12-04 10:58:59 +00:00
|
|
|
last_position: Option<u64>,
|
|
|
|
|
2016-12-04 18:24:44 +00:00
|
|
|
metadata: Option<Metadata>,
|
2017-01-05 22:46:59 +00:00
|
|
|
|
2017-02-03 14:34:17 +00:00
|
|
|
aac_sequence_header: Option<GstRc<Buffer>>,
|
|
|
|
avc_sequence_header: Option<GstRc<Buffer>>,
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl StreamingState {
|
|
|
|
fn new(audio: bool, video: bool) -> StreamingState {
|
|
|
|
StreamingState {
|
|
|
|
audio: None,
|
|
|
|
expect_audio: audio,
|
|
|
|
video: None,
|
|
|
|
expect_video: video,
|
|
|
|
got_all_streams: false,
|
|
|
|
last_position: None,
|
2016-12-04 18:24:44 +00:00
|
|
|
metadata: None,
|
2017-01-05 22:46:59 +00:00
|
|
|
aac_sequence_header: None,
|
|
|
|
avc_sequence_header: None,
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, Clone)]
|
|
|
|
struct AudioFormat {
|
|
|
|
format: flavors::SoundFormat,
|
|
|
|
rate: u16,
|
|
|
|
width: u8,
|
|
|
|
channels: u8,
|
|
|
|
bitrate: Option<u32>,
|
2017-02-03 14:34:17 +00:00
|
|
|
aac_sequence_header: Option<GstRc<Buffer>>,
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ignores bitrate
|
|
|
|
impl PartialEq for AudioFormat {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2017-01-05 22:46:59 +00:00
|
|
|
self.format.eq(&other.format) && self.rate.eq(&other.rate) &&
|
|
|
|
self.width.eq(&other.width) && self.channels.eq(&other.channels) &&
|
|
|
|
self.aac_sequence_header.eq(&other.aac_sequence_header)
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AudioFormat {
|
2017-01-05 22:46:59 +00:00
|
|
|
fn new(data_header: &flavors::AudioDataHeader,
|
|
|
|
metadata: &Option<Metadata>,
|
2017-02-03 14:34:17 +00:00
|
|
|
aac_sequence_header: &Option<GstRc<Buffer>>)
|
2017-01-05 22:46:59 +00:00
|
|
|
-> AudioFormat {
|
2016-12-04 18:24:44 +00:00
|
|
|
let numeric_rate = match (data_header.sound_format, data_header.sound_rate) {
|
2016-12-04 10:58:59 +00:00
|
|
|
(flavors::SoundFormat::NELLYMOSER_16KHZ_MONO, _) => 16000,
|
|
|
|
(flavors::SoundFormat::NELLYMOSER_8KHZ_MONO, _) => 8000,
|
|
|
|
(flavors::SoundFormat::MP3_8KHZ, _) => 8000,
|
2016-12-04 21:51:38 +00:00
|
|
|
(flavors::SoundFormat::SPEEX, _) => 16000,
|
|
|
|
(_, flavors::SoundRate::_5_5KHZ) => 5512,
|
2016-12-04 10:58:59 +00:00
|
|
|
(_, flavors::SoundRate::_11KHZ) => 11025,
|
|
|
|
(_, flavors::SoundRate::_22KHZ) => 22050,
|
|
|
|
(_, flavors::SoundRate::_44KHZ) => 44100,
|
|
|
|
};
|
|
|
|
|
2016-12-04 18:24:44 +00:00
|
|
|
let numeric_width = match data_header.sound_size {
|
2016-12-04 10:58:59 +00:00
|
|
|
flavors::SoundSize::Snd8bit => 8,
|
|
|
|
flavors::SoundSize::Snd16bit => 16,
|
|
|
|
};
|
|
|
|
|
2016-12-04 18:24:44 +00:00
|
|
|
let numeric_channels = match data_header.sound_type {
|
2016-12-04 10:58:59 +00:00
|
|
|
flavors::SoundType::SndMono => 1,
|
|
|
|
flavors::SoundType::SndStereo => 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
AudioFormat {
|
2016-12-04 18:24:44 +00:00
|
|
|
format: data_header.sound_format,
|
2016-12-04 10:58:59 +00:00
|
|
|
rate: numeric_rate,
|
|
|
|
width: numeric_width,
|
|
|
|
channels: numeric_channels,
|
2016-12-04 18:24:44 +00:00
|
|
|
bitrate: metadata.as_ref().and_then(|m| m.audio_bitrate),
|
2017-01-05 22:46:59 +00:00
|
|
|
aac_sequence_header: aac_sequence_header.clone(),
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:24:44 +00:00
|
|
|
fn update_with_metadata(&mut self, metadata: &Metadata) -> bool {
|
|
|
|
let mut changed = false;
|
|
|
|
|
|
|
|
if self.bitrate != metadata.audio_bitrate {
|
|
|
|
self.bitrate = metadata.audio_bitrate;
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
changed
|
|
|
|
}
|
|
|
|
|
2016-12-04 10:58:59 +00:00
|
|
|
fn to_string(&self) -> Option<String> {
|
2016-12-30 11:11:30 +00:00
|
|
|
self.to_caps().map(|c| c.to_string())
|
|
|
|
}
|
|
|
|
|
2017-02-03 14:34:17 +00:00
|
|
|
fn to_caps(&self) -> Option<GstRc<Caps>> {
|
2016-12-30 11:11:30 +00:00
|
|
|
let mut caps = match self.format {
|
2016-12-04 21:51:38 +00:00
|
|
|
flavors::SoundFormat::MP3 |
|
|
|
|
flavors::SoundFormat::MP3_8KHZ => {
|
2016-12-30 11:11:30 +00:00
|
|
|
Some(Caps::new_simple("audio/mpeg",
|
2017-01-13 20:45:23 +00:00
|
|
|
&[("mpegversion", &1.into()), ("layer", &3.into())]))
|
2016-12-04 21:51:38 +00:00
|
|
|
}
|
2017-01-05 22:46:59 +00:00
|
|
|
flavors::SoundFormat::PCM_NE |
|
2016-12-04 21:51:38 +00:00
|
|
|
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
|
2016-12-30 11:11:30 +00:00
|
|
|
Some(Caps::new_simple("audio/x-raw",
|
2017-01-13 20:45:23 +00:00
|
|
|
&[("layout", &"interleaved".into()),
|
2017-01-09 18:55:10 +00:00
|
|
|
("format",
|
2017-01-13 20:45:23 +00:00
|
|
|
&if self.width == 8 {
|
2017-04-10 10:30:07 +00:00
|
|
|
"U8".into()
|
|
|
|
} else {
|
|
|
|
"S16LE".into()
|
|
|
|
})]))
|
2016-12-04 21:51:38 +00:00
|
|
|
} else {
|
|
|
|
None
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-30 11:11:30 +00:00
|
|
|
flavors::SoundFormat::ADPCM => {
|
2017-01-13 20:45:23 +00:00
|
|
|
Some(Caps::new_simple("audio/x-adpcm", &[("layout", &"swf".into())]))
|
2016-12-30 11:11:30 +00:00
|
|
|
}
|
2016-12-04 21:51:38 +00:00
|
|
|
flavors::SoundFormat::NELLYMOSER_16KHZ_MONO |
|
|
|
|
flavors::SoundFormat::NELLYMOSER_8KHZ_MONO |
|
2017-01-09 18:55:10 +00:00
|
|
|
flavors::SoundFormat::NELLYMOSER => Some(Caps::new_simple("audio/x-nellymoser", &[])),
|
|
|
|
flavors::SoundFormat::PCM_ALAW => Some(Caps::new_simple("audio/x-alaw", &[])),
|
|
|
|
flavors::SoundFormat::PCM_ULAW => Some(Caps::new_simple("audio/x-mulaw", &[])),
|
2016-12-04 21:51:38 +00:00
|
|
|
flavors::SoundFormat::AAC => {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.aac_sequence_header
|
|
|
|
.as_ref()
|
|
|
|
.map(|header| {
|
|
|
|
Caps::new_simple("audio/mpeg",
|
|
|
|
&[("mpegversion", &4.into()),
|
|
|
|
("framed", &true.into()),
|
|
|
|
("stream-format", &"raw".into()),
|
|
|
|
("codec_data", &header.as_ref().into())])
|
|
|
|
})
|
2016-12-04 21:51:38 +00:00
|
|
|
}
|
|
|
|
flavors::SoundFormat::SPEEX => {
|
2017-01-14 17:04:55 +00:00
|
|
|
let header = {
|
2017-01-14 17:15:06 +00:00
|
|
|
let header_size = 80;
|
|
|
|
let mut data = Cursor::new(Vec::with_capacity(header_size));
|
|
|
|
data.write_all(b"Speex 1.1.12").unwrap();
|
|
|
|
data.write_all(&[0; 14]).unwrap();
|
2017-01-13 10:52:41 +00:00
|
|
|
data.write_u32le(1).unwrap(); // version
|
|
|
|
data.write_u32le(80).unwrap(); // header size
|
|
|
|
data.write_u32le(16000).unwrap(); // sample rate
|
|
|
|
data.write_u32le(1).unwrap(); // mode = wideband
|
|
|
|
data.write_u32le(4).unwrap(); // mode bitstream version
|
|
|
|
data.write_u32le(1).unwrap(); // channels
|
|
|
|
data.write_i32le(-1).unwrap(); // bitrate
|
|
|
|
data.write_u32le(0x50).unwrap(); // frame size
|
|
|
|
data.write_u32le(0).unwrap(); // VBR
|
|
|
|
data.write_u32le(1).unwrap(); // frames per packet
|
|
|
|
data.write_u32le(0).unwrap(); // extra headers
|
|
|
|
data.write_u32le(0).unwrap(); // reserved 1
|
|
|
|
data.write_u32le(0).unwrap(); // reserved 2
|
2017-01-14 17:04:55 +00:00
|
|
|
|
2017-01-14 17:15:06 +00:00
|
|
|
assert_eq!(data.position() as usize, header_size);
|
2017-01-14 17:04:55 +00:00
|
|
|
|
|
|
|
data.into_inner()
|
|
|
|
};
|
|
|
|
let header = Buffer::new_from_vec(header).unwrap();
|
2017-01-13 10:52:41 +00:00
|
|
|
|
2017-01-14 17:04:55 +00:00
|
|
|
let comment = {
|
2017-01-14 17:15:06 +00:00
|
|
|
let comment_size = 4 + 7 /* nothing */ + 4 + 1;
|
2017-01-14 17:04:55 +00:00
|
|
|
let mut data = Cursor::new(Vec::with_capacity(comment_size));
|
2017-01-13 10:52:41 +00:00
|
|
|
data.write_u32le(7).unwrap(); // length of "nothing"
|
2017-01-14 17:15:06 +00:00
|
|
|
data.write_all(b"nothing").unwrap(); // "vendor" string
|
2017-01-13 10:52:41 +00:00
|
|
|
data.write_u32le(0).unwrap(); // number of elements
|
2017-01-14 17:04:55 +00:00
|
|
|
data.write_u8(1).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(data.position() as usize, comment_size);
|
|
|
|
|
|
|
|
data.into_inner()
|
|
|
|
};
|
|
|
|
let comment = Buffer::new_from_vec(comment).unwrap();
|
|
|
|
|
2017-01-13 10:52:41 +00:00
|
|
|
Some(Caps::new_simple("audio/x-speex",
|
|
|
|
&[("streamheader",
|
2017-01-13 20:45:23 +00:00
|
|
|
&vec![header.into(), comment.into()].into())]))
|
2016-12-04 21:51:38 +00:00
|
|
|
}
|
|
|
|
flavors::SoundFormat::DEVICE_SPECIFIC => {
|
|
|
|
// Nobody knows
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if self.rate != 0 {
|
2017-04-12 13:44:34 +00:00
|
|
|
caps.as_mut()
|
|
|
|
.map(|c| {
|
|
|
|
c.get_mut()
|
|
|
|
.unwrap()
|
|
|
|
.set_simple(&[("rate", &(self.rate as i32).into())])
|
|
|
|
});
|
2016-12-04 21:51:38 +00:00
|
|
|
}
|
|
|
|
if self.channels != 0 {
|
2017-04-12 13:44:34 +00:00
|
|
|
caps.as_mut()
|
|
|
|
.map(|c| {
|
|
|
|
c.get_mut()
|
|
|
|
.unwrap()
|
|
|
|
.set_simple(&[("channels", &(self.channels as i32).into())])
|
|
|
|
});
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
2016-12-04 21:51:38 +00:00
|
|
|
|
2016-12-30 11:11:30 +00:00
|
|
|
caps
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, Clone)]
|
|
|
|
struct VideoFormat {
|
|
|
|
format: flavors::CodecId,
|
|
|
|
width: Option<u32>,
|
|
|
|
height: Option<u32>,
|
2017-01-15 19:56:20 +00:00
|
|
|
pixel_aspect_ratio: Option<Rational32>,
|
|
|
|
framerate: Option<Rational32>,
|
2016-12-04 10:58:59 +00:00
|
|
|
bitrate: Option<u32>,
|
2017-02-03 14:34:17 +00:00
|
|
|
avc_sequence_header: Option<GstRc<Buffer>>,
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl VideoFormat {
|
2017-01-05 22:46:59 +00:00
|
|
|
fn new(data_header: &flavors::VideoDataHeader,
|
|
|
|
metadata: &Option<Metadata>,
|
2017-02-03 14:34:17 +00:00
|
|
|
avc_sequence_header: &Option<GstRc<Buffer>>)
|
2017-01-05 22:46:59 +00:00
|
|
|
-> VideoFormat {
|
2016-12-04 10:58:59 +00:00
|
|
|
VideoFormat {
|
2016-12-04 18:24:44 +00:00
|
|
|
format: data_header.codec_id,
|
|
|
|
width: metadata.as_ref().and_then(|m| m.video_width),
|
|
|
|
height: metadata.as_ref().and_then(|m| m.video_height),
|
2017-04-12 13:44:34 +00:00
|
|
|
pixel_aspect_ratio: metadata
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|m| m.video_pixel_aspect_ratio),
|
2016-12-04 18:24:44 +00:00
|
|
|
framerate: metadata.as_ref().and_then(|m| m.video_framerate),
|
|
|
|
bitrate: metadata.as_ref().and_then(|m| m.video_bitrate),
|
2017-01-05 22:46:59 +00:00
|
|
|
avc_sequence_header: avc_sequence_header.clone(),
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_with_metadata(&mut self, metadata: &Metadata) -> bool {
|
|
|
|
let mut changed = false;
|
|
|
|
|
|
|
|
if self.width != metadata.video_width {
|
|
|
|
self.width = metadata.video_width;
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.height != metadata.video_height {
|
|
|
|
self.height = metadata.video_height;
|
|
|
|
changed = true;
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
2016-12-04 18:24:44 +00:00
|
|
|
|
|
|
|
if self.pixel_aspect_ratio != metadata.video_pixel_aspect_ratio {
|
|
|
|
self.pixel_aspect_ratio = metadata.video_pixel_aspect_ratio;
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.framerate != metadata.video_framerate {
|
|
|
|
self.framerate = metadata.video_framerate;
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.bitrate != metadata.video_bitrate {
|
|
|
|
self.bitrate = metadata.video_bitrate;
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
changed
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_string(&self) -> Option<String> {
|
2016-12-30 11:11:30 +00:00
|
|
|
self.to_caps().map(|caps| caps.to_string())
|
|
|
|
}
|
|
|
|
|
2017-02-03 14:34:17 +00:00
|
|
|
fn to_caps(&self) -> Option<GstRc<Caps>> {
|
2016-12-30 11:11:30 +00:00
|
|
|
let mut caps = match self.format {
|
2017-01-05 22:46:59 +00:00
|
|
|
flavors::CodecId::SORENSON_H263 => {
|
2017-01-13 20:45:23 +00:00
|
|
|
Some(Caps::new_simple("video/x-flash-video", &[("flvversion", &1.into())]))
|
2016-12-30 11:11:30 +00:00
|
|
|
}
|
2017-01-09 18:55:10 +00:00
|
|
|
flavors::CodecId::SCREEN => Some(Caps::new_simple("video/x-flash-screen", &[])),
|
|
|
|
flavors::CodecId::VP6 => Some(Caps::new_simple("video/x-vp6-flash", &[])),
|
|
|
|
flavors::CodecId::VP6A => Some(Caps::new_simple("video/x-vp6-flash-alpha", &[])),
|
|
|
|
flavors::CodecId::SCREEN2 => Some(Caps::new_simple("video/x-flash-screen2", &[])),
|
2016-12-04 21:51:38 +00:00
|
|
|
flavors::CodecId::H264 => {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.avc_sequence_header
|
|
|
|
.as_ref()
|
|
|
|
.map(|header| {
|
|
|
|
Caps::new_simple("video/x-h264",
|
|
|
|
&[("stream-format", &"avc".into()),
|
|
|
|
("codec_data", &header.as_ref().into())])
|
|
|
|
})
|
2017-01-05 22:46:59 +00:00
|
|
|
}
|
2017-01-09 18:55:10 +00:00
|
|
|
flavors::CodecId::H263 => Some(Caps::new_simple("video/x-h263", &[])),
|
2017-01-05 22:46:59 +00:00
|
|
|
flavors::CodecId::MPEG4Part2 => {
|
|
|
|
Some(Caps::new_simple("video/x-h263",
|
2017-01-13 20:45:23 +00:00
|
|
|
&[("mpegversion", &4.into()),
|
|
|
|
("systemstream", &false.into())]))
|
2016-12-04 21:51:38 +00:00
|
|
|
}
|
|
|
|
flavors::CodecId::JPEG => {
|
|
|
|
// Unused according to spec
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
2016-12-04 10:58:59 +00:00
|
|
|
|
2016-12-04 21:51:38 +00:00
|
|
|
if let (Some(width), Some(height)) = (self.width, self.height) {
|
2017-04-12 13:44:34 +00:00
|
|
|
caps.as_mut()
|
|
|
|
.map(|c| {
|
|
|
|
c.get_mut()
|
|
|
|
.unwrap()
|
|
|
|
.set_simple(&[("width", &(width as i32).into()),
|
|
|
|
("height", &(height as i32).into())])
|
|
|
|
});
|
2016-12-04 21:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(par) = self.pixel_aspect_ratio {
|
2017-01-15 19:56:20 +00:00
|
|
|
if *par.numer() != 0 && par.numer() != par.denom() {
|
2017-04-12 13:44:34 +00:00
|
|
|
caps.as_mut()
|
|
|
|
.map(|c| {
|
|
|
|
c.get_mut()
|
|
|
|
.unwrap()
|
|
|
|
.set_simple(&[("pixel-aspect-ratio", &par.into())])
|
|
|
|
});
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-04 21:51:38 +00:00
|
|
|
|
|
|
|
if let Some(fps) = self.framerate {
|
2017-01-15 19:56:20 +00:00
|
|
|
if *fps.numer() != 0 {
|
2017-04-12 13:44:34 +00:00
|
|
|
caps.as_mut()
|
|
|
|
.map(|c| {
|
|
|
|
c.get_mut()
|
|
|
|
.unwrap()
|
|
|
|
.set_simple(&[("framerate", &fps.into())])
|
|
|
|
});
|
2016-12-04 21:51:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-30 11:11:30 +00:00
|
|
|
caps
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignores bitrate
|
|
|
|
impl PartialEq for VideoFormat {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.format.eq(&other.format) && self.width.eq(&other.width) &&
|
|
|
|
self.height.eq(&other.height) &&
|
|
|
|
self.pixel_aspect_ratio.eq(&other.pixel_aspect_ratio) &&
|
2017-01-05 22:46:59 +00:00
|
|
|
self.framerate.eq(&other.framerate) &&
|
|
|
|
self.avc_sequence_header.eq(&other.avc_sequence_header)
|
2016-12-04 10:58:59 +00:00
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:24:44 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
|
struct Metadata {
|
|
|
|
duration: Option<u64>,
|
|
|
|
|
|
|
|
creation_date: Option<String>,
|
|
|
|
creator: Option<String>,
|
|
|
|
title: Option<String>,
|
|
|
|
metadata_creator: Option<String>, /* TODO: seek_table: _,
|
|
|
|
* filepositions / times metadata arrays */
|
|
|
|
|
|
|
|
audio_bitrate: Option<u32>,
|
|
|
|
|
|
|
|
video_width: Option<u32>,
|
|
|
|
video_height: Option<u32>,
|
2017-01-15 19:56:20 +00:00
|
|
|
video_pixel_aspect_ratio: Option<Rational32>,
|
|
|
|
video_framerate: Option<Rational32>,
|
2016-12-04 18:24:44 +00:00
|
|
|
video_bitrate: Option<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Metadata {
|
|
|
|
fn new(script_data: &flavors::ScriptData) -> Metadata {
|
|
|
|
assert_eq!(script_data.name, "onMetaData");
|
|
|
|
|
|
|
|
let mut metadata = Metadata {
|
|
|
|
duration: None,
|
|
|
|
creation_date: None,
|
|
|
|
creator: None,
|
|
|
|
title: None,
|
|
|
|
metadata_creator: None,
|
|
|
|
audio_bitrate: None,
|
|
|
|
video_width: None,
|
|
|
|
video_height: None,
|
|
|
|
video_pixel_aspect_ratio: None,
|
|
|
|
video_framerate: None,
|
|
|
|
video_bitrate: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let args = match script_data.arguments {
|
2016-12-17 22:48:58 +00:00
|
|
|
flavors::ScriptDataValue::Object(ref objects) |
|
2017-01-08 23:44:55 +00:00
|
|
|
flavors::ScriptDataValue::ECMAArray(ref objects) => objects,
|
2016-12-04 18:24:44 +00:00
|
|
|
_ => return metadata,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut par_n = None;
|
|
|
|
let mut par_d = None;
|
|
|
|
|
|
|
|
for arg in args {
|
|
|
|
match (arg.name, &arg.data) {
|
|
|
|
("duration", &flavors::ScriptDataValue::Number(duration)) => {
|
|
|
|
metadata.duration = Some((duration * 1000.0 * 1000.0 * 1000.0) as u64);
|
|
|
|
}
|
|
|
|
("creationdate", &flavors::ScriptDataValue::String(date)) => {
|
|
|
|
metadata.creation_date = Some(String::from(date));
|
|
|
|
}
|
|
|
|
("creator", &flavors::ScriptDataValue::String(creator)) => {
|
|
|
|
metadata.creator = Some(String::from(creator));
|
|
|
|
}
|
|
|
|
("title", &flavors::ScriptDataValue::String(title)) => {
|
|
|
|
metadata.title = Some(String::from(title));
|
|
|
|
}
|
|
|
|
("metadatacreator", &flavors::ScriptDataValue::String(creator)) => {
|
|
|
|
metadata.metadata_creator = Some(String::from(creator));
|
|
|
|
}
|
|
|
|
("audiodatarate", &flavors::ScriptDataValue::Number(datarate)) => {
|
|
|
|
metadata.audio_bitrate = Some((datarate * 1024.0) as u32);
|
|
|
|
}
|
|
|
|
("width", &flavors::ScriptDataValue::Number(width)) => {
|
|
|
|
metadata.video_width = Some(width as u32);
|
|
|
|
}
|
|
|
|
("height", &flavors::ScriptDataValue::Number(height)) => {
|
|
|
|
metadata.video_height = Some(height as u32);
|
|
|
|
}
|
2016-12-05 17:47:10 +00:00
|
|
|
("framerate", &flavors::ScriptDataValue::Number(framerate)) if framerate >= 0.0 => {
|
2017-01-15 19:56:20 +00:00
|
|
|
if let Some(framerate) = utils::f64_to_fraction(framerate) {
|
|
|
|
metadata.video_framerate = Some(framerate);
|
2016-12-05 17:47:10 +00:00
|
|
|
}
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
2017-01-15 19:56:20 +00:00
|
|
|
("AspectRatioX", &flavors::ScriptDataValue::Number(par_x)) if par_x > 0.0 => {
|
|
|
|
par_n = Some(par_x as i32);
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
2017-01-15 19:56:20 +00:00
|
|
|
("AspectRatioY", &flavors::ScriptDataValue::Number(par_y)) if par_y > 0.0 => {
|
|
|
|
par_d = Some(par_y as i32);
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
|
|
|
("videodatarate", &flavors::ScriptDataValue::Number(datarate)) => {
|
|
|
|
metadata.video_bitrate = Some((datarate * 1024.0) as u32);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let (Some(par_n), Some(par_d)) = (par_n, par_d) {
|
2017-01-15 19:56:20 +00:00
|
|
|
metadata.video_pixel_aspect_ratio = Some(Rational32::new(par_n, par_d));
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
metadata
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct FlvDemux {
|
2016-12-25 11:16:12 +00:00
|
|
|
logger: Logger,
|
2016-12-03 22:57:42 +00:00
|
|
|
state: State,
|
|
|
|
adapter: Adapter,
|
|
|
|
// Only in >= State::Streaming
|
|
|
|
streaming_state: Option<StreamingState>,
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FlvDemux {
|
2016-12-25 11:16:12 +00:00
|
|
|
pub fn new(element: Element) -> FlvDemux {
|
2016-12-03 22:57:42 +00:00
|
|
|
FlvDemux {
|
2016-12-25 11:16:12 +00:00
|
|
|
logger: Logger::root(GstDebugDrain::new(Some(&element),
|
|
|
|
"rsflvdemux",
|
|
|
|
0,
|
|
|
|
"Rust FLV demuxer"),
|
2017-04-12 13:44:34 +00:00
|
|
|
o!()),
|
2016-12-03 22:57:42 +00:00
|
|
|
state: State::Stopped,
|
|
|
|
adapter: Adapter::new(),
|
|
|
|
streaming_state: None,
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2016-12-25 11:16:12 +00:00
|
|
|
pub fn new_boxed(element: Element) -> Box<Demuxer> {
|
|
|
|
Box::new(FlvDemux::new(element))
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
fn handle_script_tag(&mut self,
|
2016-11-24 14:29:43 +00:00
|
|
|
tag_header: &flavors::TagHeader)
|
|
|
|
-> Result<HandleBufferResult, FlowError> {
|
2016-12-04 18:24:44 +00:00
|
|
|
if self.adapter.get_available() < (15 + tag_header.data_size) as usize {
|
|
|
|
return Ok(HandleBufferResult::NeedMoreData);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.adapter.flush(15).unwrap();
|
|
|
|
|
2017-04-12 13:44:34 +00:00
|
|
|
let buffer = self.adapter
|
|
|
|
.get_buffer(tag_header.data_size as usize)
|
|
|
|
.unwrap();
|
2016-12-04 18:24:44 +00:00
|
|
|
let map = buffer.map_read().unwrap();
|
|
|
|
let data = map.as_slice();
|
|
|
|
|
|
|
|
match flavors::script_data(data) {
|
|
|
|
IResult::Done(_, ref script_data) if script_data.name == "onMetaData" => {
|
2016-12-27 16:14:39 +00:00
|
|
|
trace!(self.logger, "Got script tag: {:?}", script_data);
|
|
|
|
|
2016-12-04 18:24:44 +00:00
|
|
|
let metadata = Metadata::new(script_data);
|
2016-12-27 16:14:39 +00:00
|
|
|
debug!(self.logger, "Got metadata: {:?}", metadata);
|
|
|
|
|
|
|
|
let streaming_state = self.streaming_state.as_mut().unwrap();
|
2016-12-04 18:24:44 +00:00
|
|
|
|
2017-04-12 13:44:34 +00:00
|
|
|
let audio_changed = streaming_state
|
|
|
|
.audio
|
2016-12-04 18:24:44 +00:00
|
|
|
.as_mut()
|
|
|
|
.map(|a| a.update_with_metadata(&metadata))
|
|
|
|
.unwrap_or(false);
|
2017-04-12 13:44:34 +00:00
|
|
|
let video_changed = streaming_state
|
|
|
|
.video
|
2016-12-04 18:24:44 +00:00
|
|
|
.as_mut()
|
|
|
|
.map(|v| v.update_with_metadata(&metadata))
|
|
|
|
.unwrap_or(false);
|
|
|
|
streaming_state.metadata = Some(metadata);
|
|
|
|
|
|
|
|
if audio_changed || video_changed {
|
|
|
|
let mut streams = Vec::new();
|
|
|
|
|
|
|
|
if audio_changed {
|
2017-04-10 10:30:07 +00:00
|
|
|
if let Some(caps) =
|
|
|
|
streaming_state.audio.as_ref().and_then(|a| a.to_caps()) {
|
2016-12-30 11:11:30 +00:00
|
|
|
streams.push(Stream::new(AUDIO_STREAM_ID, caps, String::from("audio")));
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if video_changed {
|
2017-04-10 10:30:07 +00:00
|
|
|
if let Some(caps) =
|
|
|
|
streaming_state.video.as_ref().and_then(|v| v.to_caps()) {
|
2016-12-30 11:11:30 +00:00
|
|
|
streams.push(Stream::new(VIDEO_STREAM_ID, caps, String::from("video")));
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ok(HandleBufferResult::StreamsChanged(streams));
|
|
|
|
}
|
|
|
|
}
|
2016-12-27 16:14:39 +00:00
|
|
|
IResult::Done(_, ref script_data) => {
|
|
|
|
trace!(self.logger, "Got script tag: {:?}", script_data);
|
|
|
|
}
|
2016-12-04 18:24:44 +00:00
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
Ok(HandleBufferResult::Again)
|
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
fn update_audio_stream(&mut self,
|
2016-12-04 10:58:59 +00:00
|
|
|
data_header: &flavors::AudioDataHeader)
|
2016-11-24 14:29:43 +00:00
|
|
|
-> Result<HandleBufferResult, FlowError> {
|
2016-12-27 16:14:39 +00:00
|
|
|
let logger = self.logger.clone();
|
|
|
|
trace!(logger, "Got audio data header: {:?}", data_header);
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let streaming_state = self.streaming_state.as_mut().unwrap();
|
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
let new_audio_format = AudioFormat::new(data_header,
|
|
|
|
&streaming_state.metadata,
|
|
|
|
&streaming_state.aac_sequence_header);
|
2016-12-04 10:58:59 +00:00
|
|
|
|
|
|
|
if streaming_state.audio.as_ref() != Some(&new_audio_format) {
|
2016-12-27 16:14:39 +00:00
|
|
|
debug!(logger, "Got new audio format: {:?}", new_audio_format);
|
2016-12-04 10:58:59 +00:00
|
|
|
let new_stream = streaming_state.audio == None;
|
|
|
|
|
2016-12-30 11:11:30 +00:00
|
|
|
let caps = new_audio_format.to_caps();
|
|
|
|
if let Some(caps) = caps {
|
2016-12-04 10:58:59 +00:00
|
|
|
streaming_state.audio = Some(new_audio_format);
|
2016-12-30 11:11:30 +00:00
|
|
|
let stream = Stream::new(AUDIO_STREAM_ID, caps, String::from("audio"));
|
2016-12-04 10:58:59 +00:00
|
|
|
if new_stream {
|
|
|
|
return Ok(HandleBufferResult::StreamAdded(stream));
|
|
|
|
} else {
|
|
|
|
return Ok(HandleBufferResult::StreamChanged(stream));
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2016-12-27 16:14:39 +00:00
|
|
|
} else {
|
2017-01-05 22:46:59 +00:00
|
|
|
streaming_state.audio = None;
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
if !streaming_state.got_all_streams && streaming_state.audio != None &&
|
2016-12-04 10:58:59 +00:00
|
|
|
(streaming_state.expect_video && streaming_state.video != None ||
|
|
|
|
!streaming_state.expect_video) {
|
2016-12-03 22:57:42 +00:00
|
|
|
streaming_state.got_all_streams = true;
|
2016-11-24 14:29:43 +00:00
|
|
|
return Ok(HandleBufferResult::HaveAllStreams);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(HandleBufferResult::Again)
|
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
fn handle_audio_tag(&mut self,
|
2016-11-24 14:29:43 +00:00
|
|
|
tag_header: &flavors::TagHeader,
|
2016-12-04 10:58:59 +00:00
|
|
|
data_header: &flavors::AudioDataHeader)
|
2016-11-24 14:29:43 +00:00
|
|
|
-> Result<HandleBufferResult, FlowError> {
|
2016-12-03 22:57:42 +00:00
|
|
|
let res = self.update_audio_stream(data_header);
|
2016-11-24 14:29:43 +00:00
|
|
|
match res {
|
|
|
|
Ok(HandleBufferResult::Again) => (),
|
|
|
|
_ => return res,
|
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
if self.adapter.get_available() < (15 + tag_header.data_size) as usize {
|
2016-11-24 14:29:43 +00:00
|
|
|
return Ok(HandleBufferResult::NeedMoreData);
|
|
|
|
}
|
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
// AAC special case
|
|
|
|
if data_header.sound_format == flavors::SoundFormat::AAC {
|
|
|
|
// Not big enough for the AAC packet header, ship!
|
|
|
|
if tag_header.data_size < 1 + 1 {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.adapter
|
|
|
|
.flush(15 + tag_header.data_size as usize)
|
|
|
|
.unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
warn!(self.logger,
|
|
|
|
"Too small packet for AAC packet header {}",
|
|
|
|
15 + tag_header.data_size);
|
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut data = [0u8; 17];
|
|
|
|
self.adapter.peek_into(&mut data).unwrap();
|
|
|
|
match flavors::aac_audio_packet_header(&data[16..]) {
|
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
IResult::Done(_, header) => {
|
|
|
|
trace!(self.logger, "Got AAC packet header {:?}", header);
|
|
|
|
match header.packet_type {
|
|
|
|
flavors::AACPacketType::SequenceHeader => {
|
|
|
|
self.adapter.flush(15 + 1 + 1).unwrap();
|
|
|
|
let buffer = self.adapter
|
|
|
|
.get_buffer((tag_header.data_size - 1 - 1) as usize)
|
|
|
|
.unwrap();
|
|
|
|
debug!(self.logger,
|
|
|
|
"Got AAC sequence header {:?} of size {}",
|
|
|
|
buffer,
|
|
|
|
tag_header.data_size - 1 - 1);
|
|
|
|
|
|
|
|
let streaming_state = self.streaming_state.as_mut().unwrap();
|
|
|
|
streaming_state.aac_sequence_header = Some(buffer);
|
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
flavors::AACPacketType::Raw => {
|
|
|
|
// fall through
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let streaming_state = self.streaming_state.as_ref().unwrap();
|
|
|
|
|
|
|
|
if streaming_state.audio == None {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.adapter
|
|
|
|
.flush((tag_header.data_size + 15) as usize)
|
|
|
|
.unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
|
|
|
let audio = streaming_state.audio.as_ref().unwrap();
|
2016-12-03 22:57:42 +00:00
|
|
|
self.adapter.flush(16).unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
|
|
|
|
let offset = match audio.format {
|
|
|
|
flavors::SoundFormat::AAC => 1,
|
|
|
|
_ => 0,
|
|
|
|
};
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
if tag_header.data_size == 0 {
|
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
if tag_header.data_size < offset {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.adapter
|
|
|
|
.flush((tag_header.data_size - 1) as usize)
|
|
|
|
.unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
|
|
|
if offset > 0 {
|
|
|
|
self.adapter.flush(offset as usize).unwrap();
|
|
|
|
}
|
|
|
|
|
2017-04-12 13:44:34 +00:00
|
|
|
let mut buffer = self.adapter
|
|
|
|
.get_buffer((tag_header.data_size - 1 - offset) as usize)
|
|
|
|
.unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
|
2017-02-03 14:34:17 +00:00
|
|
|
{
|
|
|
|
let buffer = buffer.get_mut().unwrap();
|
|
|
|
buffer.set_pts(Some((tag_header.timestamp as u64) * 1000 * 1000));
|
|
|
|
}
|
|
|
|
|
2016-12-27 16:14:39 +00:00
|
|
|
trace!(self.logger,
|
|
|
|
"Outputting audio buffer {:?} for tag {:?} of size {}",
|
|
|
|
buffer,
|
|
|
|
tag_header,
|
|
|
|
tag_header.data_size - 1);
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
Ok(HandleBufferResult::BufferForStream(AUDIO_STREAM_ID, buffer))
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
fn update_video_stream(&mut self,
|
2016-12-04 10:58:59 +00:00
|
|
|
data_header: &flavors::VideoDataHeader)
|
2016-11-24 14:29:43 +00:00
|
|
|
-> Result<HandleBufferResult, FlowError> {
|
2016-12-27 16:14:39 +00:00
|
|
|
let logger = self.logger.clone();
|
|
|
|
trace!(logger, "Got video data header: {:?}", data_header);
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let streaming_state = self.streaming_state.as_mut().unwrap();
|
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
let new_video_format = VideoFormat::new(data_header,
|
|
|
|
&streaming_state.metadata,
|
|
|
|
&streaming_state.avc_sequence_header);
|
2016-12-04 10:58:59 +00:00
|
|
|
|
|
|
|
if streaming_state.video.as_ref() != Some(&new_video_format) {
|
2016-12-27 16:14:39 +00:00
|
|
|
debug!(logger, "Got new video format: {:?}", new_video_format);
|
|
|
|
|
2016-12-04 10:58:59 +00:00
|
|
|
let new_stream = streaming_state.video == None;
|
|
|
|
|
2016-12-30 11:11:30 +00:00
|
|
|
let caps = new_video_format.to_caps();
|
|
|
|
if let Some(caps) = caps {
|
2016-12-04 10:58:59 +00:00
|
|
|
streaming_state.video = Some(new_video_format);
|
2016-12-30 11:11:30 +00:00
|
|
|
let stream = Stream::new(VIDEO_STREAM_ID, caps, String::from("video"));
|
2016-12-04 10:58:59 +00:00
|
|
|
if new_stream {
|
|
|
|
return Ok(HandleBufferResult::StreamAdded(stream));
|
|
|
|
} else {
|
|
|
|
return Ok(HandleBufferResult::StreamChanged(stream));
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2016-12-27 16:14:39 +00:00
|
|
|
} else {
|
2017-01-05 22:46:59 +00:00
|
|
|
streaming_state.video = None;
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
if !streaming_state.got_all_streams && streaming_state.video != None &&
|
2016-12-04 10:58:59 +00:00
|
|
|
(streaming_state.expect_audio && streaming_state.audio != None ||
|
|
|
|
!streaming_state.expect_audio) {
|
2016-12-03 22:57:42 +00:00
|
|
|
streaming_state.got_all_streams = true;
|
2016-11-24 14:29:43 +00:00
|
|
|
return Ok(HandleBufferResult::HaveAllStreams);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(HandleBufferResult::Again)
|
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
fn handle_video_tag(&mut self,
|
2016-11-24 14:29:43 +00:00
|
|
|
tag_header: &flavors::TagHeader,
|
2016-12-04 10:58:59 +00:00
|
|
|
data_header: &flavors::VideoDataHeader)
|
2016-11-24 14:29:43 +00:00
|
|
|
-> Result<HandleBufferResult, FlowError> {
|
2016-12-03 22:57:42 +00:00
|
|
|
let res = self.update_video_stream(data_header);
|
2016-11-24 14:29:43 +00:00
|
|
|
match res {
|
|
|
|
Ok(HandleBufferResult::Again) => (),
|
|
|
|
_ => return res,
|
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
if self.adapter.get_available() < (15 + tag_header.data_size) as usize {
|
2016-11-24 14:29:43 +00:00
|
|
|
return Ok(HandleBufferResult::NeedMoreData);
|
|
|
|
}
|
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
let mut cts = 0;
|
|
|
|
|
|
|
|
// AVC/H264 special case
|
|
|
|
if data_header.codec_id == flavors::CodecId::H264 {
|
|
|
|
// Not big enough for the AVC packet header, ship!
|
|
|
|
if tag_header.data_size < 1 + 4 {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.adapter
|
|
|
|
.flush(15 + tag_header.data_size as usize)
|
|
|
|
.unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
warn!(self.logger,
|
|
|
|
"Too small packet for AVC packet header {}",
|
|
|
|
15 + tag_header.data_size);
|
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut data = [0u8; 20];
|
|
|
|
self.adapter.peek_into(&mut data).unwrap();
|
|
|
|
match flavors::avc_video_packet_header(&data[16..]) {
|
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
IResult::Done(_, header) => {
|
|
|
|
trace!(self.logger, "Got AVC packet header {:?}", header);
|
|
|
|
match header.packet_type {
|
|
|
|
flavors::AVCPacketType::SequenceHeader => {
|
|
|
|
self.adapter.flush(15 + 1 + 4).unwrap();
|
|
|
|
let buffer = self.adapter
|
|
|
|
.get_buffer((tag_header.data_size - 1 - 4) as usize)
|
|
|
|
.unwrap();
|
|
|
|
debug!(self.logger,
|
|
|
|
"Got AVC sequence header {:?} of size {}",
|
|
|
|
buffer,
|
|
|
|
tag_header.data_size - 1 - 4);
|
|
|
|
|
|
|
|
let streaming_state = self.streaming_state.as_mut().unwrap();
|
|
|
|
streaming_state.avc_sequence_header = Some(buffer);
|
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
flavors::AVCPacketType::NALU => {
|
|
|
|
cts = header.composition_time;
|
|
|
|
}
|
|
|
|
flavors::AVCPacketType::EndOfSequence => {
|
|
|
|
// Skip
|
2017-04-12 13:44:34 +00:00
|
|
|
self.adapter
|
|
|
|
.flush(15 + tag_header.data_size as usize)
|
|
|
|
.unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let streaming_state = self.streaming_state.as_ref().unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
|
|
|
|
if streaming_state.video == None {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.adapter
|
|
|
|
.flush((tag_header.data_size + 15) as usize)
|
|
|
|
.unwrap();
|
2017-01-05 22:46:59 +00:00
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let video = streaming_state.video.as_ref().unwrap();
|
2016-12-04 10:58:59 +00:00
|
|
|
let is_keyframe = data_header.frame_type == flavors::FrameType::Key;
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
self.adapter.flush(16).unwrap();
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2017-01-05 22:46:59 +00:00
|
|
|
let offset = match video.format {
|
|
|
|
flavors::CodecId::VP6 |
|
|
|
|
flavors::CodecId::VP6A => 1,
|
|
|
|
flavors::CodecId::H264 => 4,
|
|
|
|
_ => 0,
|
2016-11-24 14:29:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if tag_header.data_size == 0 {
|
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
|
|
|
if tag_header.data_size < offset {
|
2017-04-12 13:44:34 +00:00
|
|
|
self.adapter
|
|
|
|
.flush((tag_header.data_size - 1) as usize)
|
|
|
|
.unwrap();
|
2016-11-24 14:29:43 +00:00
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
|
|
|
|
if offset > 0 {
|
2016-12-03 22:57:42 +00:00
|
|
|
self.adapter.flush(offset as usize).unwrap();
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2017-04-12 13:44:34 +00:00
|
|
|
let mut buffer = self.adapter
|
|
|
|
.get_buffer((tag_header.data_size - 1 - offset) as usize)
|
|
|
|
.unwrap();
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2017-02-03 14:34:17 +00:00
|
|
|
{
|
|
|
|
let buffer = buffer.get_mut().unwrap();
|
|
|
|
if !is_keyframe {
|
|
|
|
buffer.set_flags(BUFFER_FLAG_DELTA_UNIT);
|
|
|
|
}
|
|
|
|
buffer.set_dts(Some((tag_header.timestamp as u64) * 1000 * 1000));
|
|
|
|
|
|
|
|
// Prevent negative numbers
|
|
|
|
let pts = if cts < 0 && tag_header.timestamp < (-cts) as u32 {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
((tag_header.timestamp as i64) + (cts as i64)) as u64
|
|
|
|
};
|
|
|
|
buffer.set_pts(Some(pts * 1000 * 1000));
|
|
|
|
}
|
2017-01-05 22:46:59 +00:00
|
|
|
|
2016-12-27 16:14:39 +00:00
|
|
|
trace!(self.logger,
|
|
|
|
"Outputting video buffer {:?} for tag {:?} of size {}, keyframe: {}",
|
|
|
|
buffer,
|
|
|
|
tag_header,
|
|
|
|
tag_header.data_size - 1 - offset,
|
|
|
|
is_keyframe);
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
Ok(HandleBufferResult::BufferForStream(VIDEO_STREAM_ID, buffer))
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
fn update_state(&mut self) -> Result<HandleBufferResult, FlowError> {
|
|
|
|
match self.state {
|
|
|
|
State::Stopped => unreachable!(),
|
|
|
|
State::NeedHeader => {
|
|
|
|
while self.adapter.get_available() >= 9 {
|
|
|
|
let mut data = [0u8; 9];
|
|
|
|
self.adapter.peek_into(&mut data).unwrap();
|
|
|
|
|
|
|
|
match flavors::header(&data) {
|
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
// fall through
|
|
|
|
}
|
2016-12-04 18:24:44 +00:00
|
|
|
IResult::Done(_, ref header) => {
|
2016-12-27 16:14:39 +00:00
|
|
|
debug!(self.logger, "Found FLV header: {:?}", header);
|
|
|
|
|
2016-12-04 10:58:59 +00:00
|
|
|
let skip = if header.offset < 9 {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
header.offset - 9
|
|
|
|
};
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
self.adapter.flush(9).unwrap();
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-04 10:58:59 +00:00
|
|
|
self.state = State::Skipping {
|
|
|
|
audio: header.audio,
|
|
|
|
video: header.video,
|
|
|
|
skip_left: skip,
|
|
|
|
};
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
return Ok(HandleBufferResult::Again);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.adapter.flush(1).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(HandleBufferResult::NeedMoreData)
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2017-04-12 13:44:34 +00:00
|
|
|
State::Skipping {
|
|
|
|
audio,
|
|
|
|
video,
|
|
|
|
skip_left: 0,
|
|
|
|
} => {
|
2016-12-03 22:57:42 +00:00
|
|
|
self.state = State::Streaming;
|
2016-12-04 10:58:59 +00:00
|
|
|
self.streaming_state = Some(StreamingState::new(audio, video));
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
Ok(HandleBufferResult::Again)
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2016-12-04 10:58:59 +00:00
|
|
|
State::Skipping { ref mut skip_left, .. } => {
|
2016-12-03 22:57:42 +00:00
|
|
|
let skip = cmp::min(self.adapter.get_available(), *skip_left as usize);
|
|
|
|
self.adapter.flush(skip).unwrap();
|
|
|
|
*skip_left -= skip as u32;
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
Ok(HandleBufferResult::Again)
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2016-12-03 22:57:42 +00:00
|
|
|
State::Streaming => {
|
|
|
|
if self.adapter.get_available() < 16 {
|
|
|
|
return Ok(HandleBufferResult::NeedMoreData);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut data = [0u8; 16];
|
|
|
|
self.adapter.peek_into(&mut data).unwrap();
|
|
|
|
|
|
|
|
match nom::be_u32(&data[0..4]) {
|
2016-11-24 14:29:43 +00:00
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
2016-12-27 16:14:39 +00:00
|
|
|
IResult::Done(_, previous_size) => {
|
|
|
|
trace!(self.logger, "Previous tag size {}", previous_size);
|
2016-12-03 22:57:42 +00:00
|
|
|
// Nothing to do here, we just consume it for now
|
|
|
|
}
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let tag_header = match flavors::tag_header(&data[4..]) {
|
2016-11-24 14:29:43 +00:00
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
2016-12-03 22:57:42 +00:00
|
|
|
IResult::Done(_, tag_header) => tag_header,
|
2016-11-24 14:29:43 +00:00
|
|
|
};
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let res = match tag_header.tag_type {
|
2016-12-27 16:14:39 +00:00
|
|
|
flavors::TagType::Script => {
|
2017-01-08 23:44:55 +00:00
|
|
|
trace!(self.logger, "Found script tag");
|
2016-12-27 16:14:39 +00:00
|
|
|
|
|
|
|
self.handle_script_tag(&tag_header)
|
|
|
|
}
|
2016-12-03 22:57:42 +00:00
|
|
|
flavors::TagType::Audio => {
|
2016-12-27 16:14:39 +00:00
|
|
|
trace!(self.logger, "Found audio tag");
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let data_header = match flavors::audio_data_header(&data[15..]) {
|
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
unimplemented!();
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2016-12-03 22:57:42 +00:00
|
|
|
IResult::Done(_, data_header) => data_header,
|
|
|
|
};
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-04 10:58:59 +00:00
|
|
|
self.handle_audio_tag(&tag_header, &data_header)
|
2016-12-03 22:57:42 +00:00
|
|
|
}
|
|
|
|
flavors::TagType::Video => {
|
2016-12-27 16:14:39 +00:00
|
|
|
trace!(self.logger, "Found video tag");
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
let data_header = match flavors::video_data_header(&data[15..]) {
|
|
|
|
IResult::Error(_) |
|
|
|
|
IResult::Incomplete(_) => {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
IResult::Done(_, data_header) => data_header,
|
|
|
|
};
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-04 10:58:59 +00:00
|
|
|
self.handle_video_tag(&tag_header, &data_header)
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2016-12-03 22:57:42 +00:00
|
|
|
};
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
if let Ok(HandleBufferResult::BufferForStream(_, ref buffer)) = res {
|
|
|
|
let streaming_state = self.streaming_state.as_mut().unwrap();
|
|
|
|
|
|
|
|
if let Some(pts) = buffer.get_pts() {
|
2017-04-12 13:44:34 +00:00
|
|
|
streaming_state.last_position = streaming_state
|
|
|
|
.last_position
|
2016-12-03 22:57:42 +00:00
|
|
|
.map(|last| cmp::max(last, pts))
|
|
|
|
.or_else(|| Some(pts));
|
|
|
|
} else if let Some(dts) = buffer.get_dts() {
|
2017-04-12 13:44:34 +00:00
|
|
|
streaming_state.last_position = streaming_state
|
|
|
|
.last_position
|
2016-12-03 22:57:42 +00:00
|
|
|
.map(|last| cmp::max(last, dts))
|
|
|
|
.or_else(|| Some(dts));
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
res
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Demuxer for FlvDemux {
|
|
|
|
fn start(&mut self,
|
|
|
|
_upstream_size: Option<u64>,
|
|
|
|
_random_access: bool)
|
|
|
|
-> Result<(), ErrorMessage> {
|
2016-12-03 22:57:42 +00:00
|
|
|
self.state = State::NeedHeader;
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stop(&mut self) -> Result<(), ErrorMessage> {
|
2016-12-03 22:57:42 +00:00
|
|
|
self.state = State::Stopped;
|
|
|
|
self.adapter.clear();
|
|
|
|
self.streaming_state = None;
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn seek(&mut self, start: u64, stop: Option<u64>) -> Result<SeekResult, ErrorMessage> {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
|
2017-02-03 14:34:17 +00:00
|
|
|
fn handle_buffer(&mut self,
|
|
|
|
buffer: Option<GstRc<Buffer>>)
|
|
|
|
-> Result<HandleBufferResult, FlowError> {
|
2016-11-24 14:29:43 +00:00
|
|
|
if let Some(buffer) = buffer {
|
2016-12-03 22:57:42 +00:00
|
|
|
self.adapter.push(buffer);
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
2016-12-03 22:57:42 +00:00
|
|
|
self.update_state()
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn end_of_stream(&mut self) -> Result<(), ErrorMessage> {
|
|
|
|
// nothing to do here, all data we have left is incomplete
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_seekable(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_position(&self) -> Option<u64> {
|
2016-12-03 22:57:42 +00:00
|
|
|
if let Some(StreamingState { last_position, .. }) = self.streaming_state {
|
2016-11-24 14:29:43 +00:00
|
|
|
return last_position;
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_duration(&self) -> Option<u64> {
|
2016-12-04 18:24:44 +00:00
|
|
|
if let Some(StreamingState { metadata: Some(Metadata { duration, .. }), .. }) =
|
|
|
|
self.streaming_state {
|
|
|
|
return duration;
|
|
|
|
}
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|