├── src ├── parser │ ├── pack_header.rs │ ├── descriptor │ │ ├── language_and_audio_type.rs │ │ ├── mod.rs │ │ ├── aac.rs │ │ └── hevc.rs │ ├── mod.rs │ ├── program_clock.rs │ ├── table_id.rs │ ├── adaptation_field_extension.rs │ ├── stream_id.rs │ ├── program_descriptor.rs │ ├── packet.rs │ ├── adaptation_field.rs │ ├── stream_type.rs │ └── payload.rs ├── writer │ ├── pack_header.rs │ ├── continuity_counter.rs │ ├── mod.rs │ ├── program_clock.rs │ ├── continuity_pcr.rs │ ├── table_id.rs │ ├── stream_id.rs │ ├── adaptation_field_extension.rs │ ├── adaptation_field.rs │ ├── packet.rs │ └── payload.rs ├── wrapper │ ├── mod.rs │ └── wrapper.rs ├── mpegts │ ├── descriptor │ │ ├── mod.rs │ │ ├── hevc.rs │ │ └── aac.rs │ ├── adaptation_field_extension.rs │ ├── program_clock.rs │ ├── pack_header.rs │ ├── program_association.rs │ ├── payload.rs │ ├── mod.rs │ ├── adaptation_field.rs │ ├── program_map.rs │ ├── table_id.rs │ ├── stream_id.rs │ ├── packetized_elementary_stream.rs │ ├── program_descriptor.rs │ ├── packet.rs │ └── stream_type.rs └── lib.rs ├── README.md ├── .gitignore ├── Cargo.toml ├── examples ├── wrapper.rs ├── dump.rs ├── concat.rs └── pcr_measure.rs └── LICENSE /src/parser/pack_header.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/writer/pack_header.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/parser/descriptor/language_and_audio_type.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/wrapper/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod wrapper; 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rs_mpegts 2 | MpegTS reader and writer library 3 | -------------------------------------------------------------------------------- /src/mpegts/descriptor/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod aac; 3 | pub mod hevc; 4 | -------------------------------------------------------------------------------- /src/parser/descriptor/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod aac; 3 | pub mod hevc; 4 | pub mod language_and_audio_type; 5 | -------------------------------------------------------------------------------- /src/mpegts/descriptor/hevc.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, Clone)] 3 | pub struct Hevc { 4 | pub profile_space: u8 5 | } 6 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate bitstream_io; 2 | extern crate crc; 3 | 4 | pub mod mpegts; 5 | pub mod parser; 6 | pub mod writer; 7 | pub mod wrapper; 8 | -------------------------------------------------------------------------------- /src/mpegts/descriptor/aac.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, Clone)] 3 | pub struct Aac { 4 | pub profile_and_level: u8, 5 | pub aac_type: Option, 6 | pub additional_info: Vec, 7 | } 8 | -------------------------------------------------------------------------------- /src/writer/continuity_counter.rs: -------------------------------------------------------------------------------- 1 | 2 | pub struct Stream { 3 | pub id: u16, 4 | pub counter: u8 5 | } 6 | 7 | pub struct ContinuityCounter { 8 | pub streams: Vec 9 | } 10 | -------------------------------------------------------------------------------- /src/mpegts/adaptation_field_extension.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, Clone)] 3 | pub struct AdaptationFieldExtension { 4 | pub legal_time_window: Option, 5 | pub piecewise_rate: Option, 6 | pub seamless_splice: Option 7 | } 8 | -------------------------------------------------------------------------------- /src/writer/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod table_id; 3 | pub mod stream_id; 4 | pub mod continuity_counter; 5 | pub mod continuity_pcr; 6 | pub mod packet; 7 | pub mod adaptation_field; 8 | pub mod adaptation_field_extension; 9 | pub mod program_clock; 10 | pub mod payload; 11 | -------------------------------------------------------------------------------- /src/mpegts/program_clock.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, Clone)] 3 | pub struct ProgramClock { 4 | pub base: u64, 5 | pub extension: u16 6 | } 7 | 8 | impl ProgramClock { 9 | pub fn get(&self) -> u64 { 10 | return self.base * 300 + self.extension as u64; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/mpegts/pack_header.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug)] 3 | pub struct PackHeader { 4 | pub system_clock_reference_base: u64, 5 | pub system_clock_reference_extension: u16, 6 | pub program_mux_rate: u32, 7 | pub stuffing_size: u8, 8 | // pub system_header: Option 9 | } 10 | -------------------------------------------------------------------------------- /src/mpegts/program_association.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, Clone)] 3 | pub struct Association { 4 | pub program_number: u16, 5 | pub program_map_pid: u16, 6 | } 7 | 8 | #[derive(Debug, Clone)] 9 | pub struct ProgramAssociation { 10 | pub transport_stream_id: u16, 11 | pub table: Vec 12 | } 13 | -------------------------------------------------------------------------------- /src/parser/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod packet; 3 | pub mod adaptation_field; 4 | pub mod adaptation_field_extension; 5 | pub mod program_clock; 6 | pub mod payload; 7 | pub mod stream_id; 8 | pub mod stream_type; 9 | pub mod table_id; 10 | pub mod pack_header; 11 | pub mod program_descriptor; 12 | pub mod descriptor; 13 | -------------------------------------------------------------------------------- /src/writer/program_clock.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitWriter}; 3 | use mpegts::program_clock::ProgramClock; 4 | 5 | pub fn write_program_clock(stream: &mut BitWriter, pc: &ProgramClock) { 6 | stream.write(33, pc.base).unwrap(); 7 | stream.write(6, 0b111111).unwrap(); 8 | stream.write(9, pc.extension).unwrap(); 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /src/mpegts/payload.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::program_association::ProgramAssociation; 3 | use mpegts::program_map::ProgramMap; 4 | use mpegts::packetized_elementary_stream::PacketizedElementaryStream; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct Payload { 8 | pub pat: Option, 9 | pub pmt: Option, 10 | pub pes: Option, 11 | } 12 | -------------------------------------------------------------------------------- /src/mpegts/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod packet; 3 | pub mod adaptation_field; 4 | pub mod adaptation_field_extension; 5 | pub mod program_clock; 6 | pub mod payload; 7 | pub mod stream_id; 8 | pub mod stream_type; 9 | pub mod table_id; 10 | pub mod program_descriptor; 11 | pub mod program_association; 12 | pub mod program_map; 13 | pub mod packetized_elementary_stream; 14 | pub mod pack_header; 15 | pub mod descriptor; 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mpegts" 3 | version = "0.1.2" 4 | authors = ["Marc-Antoine Arnaud "] 5 | description = """ 6 | Library to read/write following ITU-T Rec. H.222.0 (MpegTS) standard. 7 | """ 8 | license = "MIT" 9 | repository = "https://github.com/media-io/rs_mpegts" 10 | documentation = "https://docs.rs/mpegts" 11 | 12 | [dependencies] 13 | bitstream-io = "0.6.1" 14 | crc = "1.4.0" 15 | -------------------------------------------------------------------------------- /src/parser/program_clock.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitReader}; 3 | use mpegts::program_clock::ProgramClock; 4 | 5 | pub fn parse_program_clock(stream: &mut BitReader) -> ProgramClock { 6 | let base = stream.read::(33).unwrap(); 7 | let _reserved = stream.read::(6).unwrap(); 8 | let extension = stream.read::(9).unwrap(); 9 | 10 | ProgramClock{ 11 | base: base, 12 | extension: extension 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/mpegts/adaptation_field.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::program_clock::ProgramClock; 3 | use mpegts::adaptation_field_extension::AdaptationFieldExtension; 4 | 5 | #[derive(Debug, Clone)] 6 | pub struct AdaptationField { 7 | pub length: u8, 8 | pub discontinuity_indicator: bool, 9 | pub random_access_indicator: bool, 10 | pub elementary_stream_priority_indicator: bool, 11 | pub pcr: Option, 12 | pub opcr: Option, 13 | pub splice_countdown: Option, 14 | pub transport_private_data: Vec, 15 | pub adaptation_field_extension: Option, 16 | } 17 | -------------------------------------------------------------------------------- /src/mpegts/program_map.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::stream_id::StreamId; 3 | use mpegts::program_descriptor::ProgramDescriptor; 4 | use mpegts::descriptor::hevc::*; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct EsInfo { 8 | pub descriptor: ProgramDescriptor, 9 | pub hevc: Option, 10 | pub data: Vec 11 | } 12 | 13 | 14 | #[derive(Debug, Clone)] 15 | pub struct Program { 16 | pub stream_id: StreamId, 17 | pub elementary_pid: u16, 18 | pub es_info: EsInfo 19 | } 20 | 21 | #[derive(Debug, Clone)] 22 | pub struct ProgramMap { 23 | pub program_number: u16, 24 | pub pcr_pid: u16, 25 | pub programs: Vec 26 | } 27 | -------------------------------------------------------------------------------- /examples/wrapper.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate mpegts; 3 | 4 | use std::fs::File; 5 | use mpegts::wrapper::*; 6 | use mpegts::writer::packet::write_packets; 7 | use mpegts::writer::continuity_counter::ContinuityCounter; 8 | 9 | fn main() { 10 | 11 | let mut output_file = File::create("output.ts").unwrap(); 12 | 13 | // let program = wrapper::Program{ 14 | // id: 301 15 | // }; 16 | 17 | let wrapper = wrapper::Wrapper{ 18 | programs: vec![] 19 | }; 20 | 21 | let packets = wrapper.append_data(vec![0;100]); 22 | 23 | let mut cc = ContinuityCounter{streams: vec![]}; 24 | write_packets(&mut output_file, &packets, &mut cc); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/mpegts/table_id.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, Clone)] 3 | #[allow(non_camel_case_types)] 4 | pub enum TableId { 5 | ProgramAssociation, 6 | ConditionalAccess, 7 | ProgramMap, 8 | TransportStreamDescription, 9 | IsoIec_14496_SceneDescription, 10 | IsoIec_14496_ObjectDescription, 11 | Metadata, 12 | IsoIec_13818_11_IpmpControlInformation, 13 | IsoIec_13818_6_DsmCc_MultiprotocolEncapsulated, 14 | IsoIec_13818_6_DsmCc_UNMessages, 15 | IsoIec_13818_6_DsmCc_DownloadDataMessages, 16 | IsoIec_13818_6_DsmCc_StreamDescriptorList, 17 | IsoIec_13818_6_DsmCc_PrivatelyDefined, 18 | IsoIec_13818_6_DsmCc_Addressable, 19 | Other, 20 | Reserved, 21 | Forbidden, 22 | } 23 | -------------------------------------------------------------------------------- /examples/dump.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate mpegts; 3 | 4 | use std::io::BufReader; 5 | use std::fs::File; 6 | use std::process; 7 | use std::env; 8 | 9 | use mpegts::parser::packet::parse_next_packets; 10 | 11 | fn main() { 12 | 13 | if env::args().count() != 2 { 14 | println!("ERROR: missing filepath argument."); 15 | println!("usage:"); 16 | println!(" dump [filepath.ts]"); 17 | process::exit(0x0f00); 18 | } 19 | 20 | let path = env::args().last().unwrap(); 21 | 22 | let file = File::open(path).unwrap(); 23 | let mut stream = BufReader::new(file); 24 | 25 | loop { 26 | let packets = parse_next_packets(&mut stream).unwrap(); 27 | 28 | for packet in packets { 29 | // println!("{}", packet); 30 | println!("{:?}", packet); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/writer/continuity_pcr.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, Clone)] 3 | pub struct PcrStream { 4 | pub program_id: u16, 5 | pub pcr: u64, 6 | pub index: usize 7 | } 8 | 9 | #[derive(Debug)] 10 | pub struct ContinuityPcr { 11 | pub streams: Vec 12 | } 13 | 14 | impl ContinuityPcr { 15 | pub fn get(&mut self, program_id: u16) -> Option { 16 | for stream in self.streams.clone() { 17 | if stream.program_id == program_id { 18 | return Some(stream); 19 | } 20 | } 21 | None 22 | } 23 | 24 | pub fn update(&mut self, program_id: u16, pcr: u64, index: usize) { 25 | for stream in &mut self.streams { 26 | if stream.program_id == program_id { 27 | stream.pcr = pcr; 28 | stream.index = index; 29 | return; 30 | } 31 | } 32 | self.streams.push(PcrStream{ 33 | program_id: program_id, 34 | pcr: pcr, 35 | index: index, 36 | }) 37 | } 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 media-io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/parser/table_id.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::table_id::*; 3 | 4 | pub fn get_table_id(table_id: u8) -> TableId { 5 | match table_id { 6 | 0x00 => TableId::ProgramAssociation, 7 | 0x01 => TableId::ConditionalAccess, 8 | 0x02 => TableId::ProgramMap, 9 | 0x03 => TableId::TransportStreamDescription, 10 | 0x04 => TableId::IsoIec_14496_SceneDescription, 11 | 0x05 => TableId::IsoIec_14496_ObjectDescription, 12 | 0x06 => TableId::Metadata, 13 | 0x07 => TableId::IsoIec_13818_11_IpmpControlInformation, 14 | 15 | 0x3a => TableId::IsoIec_13818_6_DsmCc_MultiprotocolEncapsulated, 16 | 0x3b => TableId::IsoIec_13818_6_DsmCc_UNMessages, 17 | 0x3c => TableId::IsoIec_13818_6_DsmCc_DownloadDataMessages, 18 | 0x3d => TableId::IsoIec_13818_6_DsmCc_StreamDescriptorList, 19 | 0x3e => TableId::IsoIec_13818_6_DsmCc_PrivatelyDefined, 20 | 0x3f => TableId::IsoIec_13818_6_DsmCc_Addressable, 21 | 0xff => TableId::Forbidden, 22 | _ => { 23 | if (table_id >= 0x08) && (table_id <= 0x39) { 24 | TableId::Reserved 25 | } else { 26 | TableId::Other 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/mpegts/stream_id.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt; 3 | 4 | #[derive(Debug, PartialEq, Clone)] 5 | #[allow(non_camel_case_types)] 6 | pub enum StreamId { 7 | Reserved, 8 | IsoIec_11172_2_Mpeg1_Video, 9 | IsoIec_13818_2_Mpeg2_Video, 10 | IsoIec_11172_3_Mpeg1_Audio, 11 | IsoIec_13818_3_Mpeg2_Audio, 12 | IsoIec_13818_1_PrivateSection, 13 | IsoIec_13818_1_Pes, 14 | IsoIec_13522_Mheg, 15 | Itu_T_H222_0_Annex_A_Dsm_Cc, 16 | Itu_T_H222_1, 17 | IsoIec_13818_6_Dsm_Cc_Type_A, 18 | IsoIec_13818_6_Dsm_Cc_Type_B, 19 | IsoIec_13818_6_Dsm_Cc_Type_C, 20 | IsoIec_13818_6_Dsm_Cc_Type_D, 21 | IsoIec_13818_1_Auxiliary, 22 | IsoIec_13818_7_AAC_Audio, 23 | IsoIec_14496_2_Mpeg4_Video, 24 | IsoIec_14496_3_AAC_Latm_Audio, 25 | Itu_T_H264_Video, 26 | Itu_T_H265_Video, 27 | Vc1_Video, 28 | Dirac_Video, 29 | Ac3_Audio, 30 | Dts_Audio, 31 | NonMpegAudioSubpictures, 32 | PaddingStream, 33 | NavigationData, 34 | AudioStream{id: u8}, 35 | VideoStream{id: u8}, 36 | Unknown, 37 | } 38 | 39 | impl fmt::Display for StreamId { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | write!(f, "{:?}", self) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/parser/descriptor/aac.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitReader}; 3 | use mpegts::descriptor::aac::*; 4 | 5 | pub fn parse_descriptor(stream: &mut BitReader) -> Aac { 6 | let _descriptor_id = stream.read::(8).unwrap(); 7 | let descriptor_length = stream.read::(8).unwrap(); 8 | let profile_and_level = stream.read::(8).unwrap(); 9 | let aac_type_flag = stream.read_bit().unwrap(); 10 | let _reserved = stream.read_bit().unwrap(); 11 | let _reserved = stream.read_bit().unwrap(); 12 | let _reserved = stream.read_bit().unwrap(); 13 | let _reserved = stream.read_bit().unwrap(); 14 | let _reserved = stream.read_bit().unwrap(); 15 | let _reserved = stream.read_bit().unwrap(); 16 | 17 | let mut count = 2; 18 | let mut aac_type = None; 19 | if aac_type_flag { 20 | aac_type = Some(stream.read::(8).unwrap()); 21 | count += 1; 22 | } 23 | 24 | let mut additional_info = vec![0; descriptor_length as usize - count]; 25 | let _ = stream.read_bytes(&mut additional_info); 26 | 27 | Aac{ 28 | profile_and_level: profile_and_level, 29 | aac_type: aac_type, 30 | additional_info: additional_info, 31 | } 32 | } -------------------------------------------------------------------------------- /src/writer/table_id.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::table_id::*; 3 | 4 | pub fn get_table_id(table_id: TableId) -> u8 { 5 | match table_id { 6 | TableId::ProgramAssociation => 0x00, 7 | TableId::ConditionalAccess => 0x01, 8 | TableId::ProgramMap => 0x02, 9 | TableId::TransportStreamDescription => 0x03, 10 | TableId::IsoIec_14496_SceneDescription => 0x04, 11 | TableId::IsoIec_14496_ObjectDescription => 0x05, 12 | TableId::Metadata => 0x06, 13 | TableId::IsoIec_13818_11_IpmpControlInformation => 0x07, 14 | 15 | TableId::IsoIec_13818_6_DsmCc_MultiprotocolEncapsulated => 0x3a, 16 | TableId::IsoIec_13818_6_DsmCc_UNMessages => 0x3b, 17 | TableId::IsoIec_13818_6_DsmCc_DownloadDataMessages => 0x3c, 18 | TableId::IsoIec_13818_6_DsmCc_StreamDescriptorList => 0x3d, 19 | TableId::IsoIec_13818_6_DsmCc_PrivatelyDefined => 0x3e, 20 | TableId::IsoIec_13818_6_DsmCc_Addressable => 0x3f, 21 | TableId::Forbidden => 0xff, 22 | _ => unimplemented!() 23 | // _ => { 24 | // if (table_id >= 0x08) && (table_id <= 0x39) { 25 | // TableId::Reserved 26 | // } else { 27 | // TableId::Other 28 | // } 29 | // } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/mpegts/packetized_elementary_stream.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::stream_id::StreamId; 3 | 4 | #[derive(Debug, Clone)] 5 | pub enum TrickModeControl { 6 | FastForward, 7 | SlowMotion, 8 | FreezeFrame, 9 | FastReverse, 10 | SlowReverse, 11 | Reserved, 12 | } 13 | 14 | #[derive(Debug, Clone)] 15 | pub struct DsmTrickMode { 16 | pub trick_mode_control: TrickModeControl, 17 | pub info: u8 18 | } 19 | 20 | #[derive(Debug, Clone)] 21 | pub struct PesExtension { 22 | pub pes_private_data: Vec, 23 | } 24 | 25 | #[derive(Debug, Clone)] 26 | pub struct PesHeader { 27 | pub scrambling_control: u8, 28 | pub priority: bool, 29 | pub data_alignment_indicator: bool, 30 | pub copyright: bool, 31 | pub original: bool, 32 | pub pts: Option, 33 | pub dts: Option, 34 | pub escr: Option, 35 | pub es_rate: Option, 36 | pub dsm_trick_mode: Option, 37 | pub additional_copy_info: Option, 38 | pub previous_pes_packet_crc: Option, 39 | pub pes_extension: Option, 40 | pub pes_header_length: u8 41 | } 42 | 43 | #[derive(Debug, Clone)] 44 | pub struct PacketizedElementaryStream { 45 | pub stream_id: StreamId, 46 | pub header: Option, 47 | pub additional_data: Vec, 48 | } 49 | -------------------------------------------------------------------------------- /src/mpegts/program_descriptor.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt; 3 | 4 | #[derive(Debug, Clone)] 5 | #[allow(non_camel_case_types)] 6 | pub enum ProgramDescriptor { 7 | Forbidden, 8 | Video_Stream, 9 | Audio_Stream, 10 | Hierarchy, 11 | Registration, 12 | Data_Stream_Alignment, 13 | Target_Background_Grid, 14 | Video_Window, 15 | CA_Descriptor, 16 | ISO_639_Language, 17 | System_Clock, 18 | Multiplex_Buffer_Utilization, 19 | Copyright, 20 | Maximum_Bitrate, 21 | Private_Data_Indicator, 22 | Smoothing_Buffer, 23 | STD, 24 | IBP, 25 | MPEG4_Video, 26 | MPEG4_Audio, 27 | IOD, 28 | SL, 29 | FMC, 30 | External_ES_ID, 31 | MuxCode, 32 | FmxBufferSize, 33 | MultiplexBuffer, 34 | Content_Labeling, 35 | Metadata_Pointer, 36 | Metadata, 37 | Metadata_STD, 38 | AVC_Video, 39 | IPMP, 40 | AVC_Timing_And_HRD, 41 | MPEG2_AAC_Audio, 42 | FlexMuxTiming, 43 | MPEG4_Text, 44 | MPEG4_Audio_Extension, 45 | Auxiliary_Video_Stream, 46 | SVC_Extension, 47 | MVC_Extension, 48 | J2K_Video, 49 | MVC_Operation_Point, 50 | MPEG2_Stereoscopic_Video_Format, 51 | Stereoscopic_Program_Info, 52 | Stereoscopic_Video_Info, 53 | Transport_Profile, 54 | HEVC_Video, 55 | Extension, 56 | Reserved, 57 | UserPrivate, 58 | } 59 | 60 | impl fmt::Display for ProgramDescriptor { 61 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 62 | write!(f, "{:?}", self) 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/wrapper/wrapper.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::packet::Packet; 3 | use mpegts::program_association::*; 4 | use mpegts::program_map::*; 5 | use mpegts::program_descriptor::*; 6 | use mpegts::stream_id::StreamId; 7 | 8 | #[derive(Debug)] 9 | pub struct Wrapper { 10 | pub programs: Vec 11 | } 12 | 13 | impl Wrapper { 14 | pub fn append_data(self, _data: Vec) -> Vec { 15 | 16 | let program_map_pid = 256; 17 | let program_number = 1; 18 | let video_pid = 257; 19 | 20 | let pat = ProgramAssociation{ 21 | transport_stream_id: 0, 22 | table: vec![Association{ 23 | program_number: program_number, 24 | program_map_pid: program_map_pid 25 | }], 26 | }; 27 | 28 | let pmt = ProgramMap{ 29 | program_number: program_number, 30 | pcr_pid: video_pid, 31 | programs: vec![Program{ 32 | stream_id: StreamId::Itu_T_H265_Video, 33 | elementary_pid: video_pid, 34 | es_info: EsInfo{ 35 | descriptor: ProgramDescriptor::Reserved, 36 | hevc: None, 37 | data: vec![] 38 | } 39 | }], 40 | }; 41 | 42 | let pat_packet = Packet::new_pat(pat); 43 | 44 | let pmt_packet = Packet::new_pmt(program_map_pid, pmt); 45 | 46 | let mut result = vec![]; 47 | 48 | result.push(pat_packet); 49 | result.push(pmt_packet); 50 | 51 | for _i in 1..6 { 52 | result.push(Packet::new_null()); 53 | } 54 | 55 | result 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /examples/concat.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate mpegts; 3 | 4 | use std::io::BufReader; 5 | use std::fs::File; 6 | use std::process; 7 | use std::env; 8 | 9 | use mpegts::parser::packet::parse_next_packets; 10 | use mpegts::writer::packet::write_packets; 11 | use mpegts::writer::continuity_counter::ContinuityCounter; 12 | 13 | fn main() { 14 | 15 | if env::args().count() != 4 { 16 | println!("ERROR: missing filepath argument."); 17 | println!("usage:"); 18 | println!(" dump [input1.ts] [input2.ts] [output.ts]"); 19 | process::exit(0x0f00); 20 | } 21 | 22 | let source1_path = env::args().nth(1).unwrap(); 23 | 24 | let mut sources = vec![ 25 | env::args().nth(2).unwrap() 26 | ]; 27 | 28 | let output_path = env::args().nth(3).unwrap(); 29 | 30 | let mut output_file = File::create(output_path).unwrap(); 31 | 32 | let file = File::open(source1_path).unwrap(); 33 | let mut stream = BufReader::new(file); 34 | 35 | let mut cc = ContinuityCounter{streams: vec![]}; 36 | let mut count = 0; 37 | loop { 38 | match parse_next_packets(&mut stream) { 39 | Ok(packets) => { 40 | write_packets(&mut output_file, &packets, &mut cc); 41 | count += packets.len(); 42 | 43 | print!("{:?} \r", count); 44 | }, 45 | Err(_msg) => { 46 | match sources.pop() { 47 | Some(source) => { 48 | let file = File::open(source).unwrap(); 49 | stream = BufReader::new(file); 50 | }, 51 | None => { 52 | println!("No more source"); 53 | return; 54 | }, 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/parser/adaptation_field_extension.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitReader}; 3 | use mpegts::adaptation_field_extension::AdaptationFieldExtension; 4 | 5 | pub fn parse_adaptation_field_extension(stream: &mut BitReader, count: &mut usize) -> Option { 6 | let _adaptation_extension_length = stream.read::(8).unwrap(); 7 | 8 | let legal_time_window_flag = stream.read_bit().unwrap(); 9 | let piecewise_rate_flag = stream.read_bit().unwrap(); 10 | let seamless_splice_flag = stream.read_bit().unwrap(); 11 | let _reserved = stream.read::(5).unwrap(); 12 | *count += 2; 13 | 14 | let mut legal_time_window = None; 15 | let mut piecewise_rate = None; 16 | let mut seamless_splice = None; 17 | 18 | if legal_time_window_flag { 19 | legal_time_window = Some(stream.read::(16).unwrap()); 20 | *count += 2; 21 | } 22 | if piecewise_rate_flag { 23 | piecewise_rate = Some(stream.read::(24).unwrap()); 24 | *count += 3; 25 | } 26 | if seamless_splice_flag { 27 | let splice_type = stream.read::(4).unwrap(); 28 | let dts_high = stream.read::(3).unwrap(); 29 | let _marker_bit = stream.read_bit().unwrap(); 30 | let dts_medium = stream.read::(15).unwrap(); 31 | let _marker_bit = stream.read_bit().unwrap(); 32 | let dts_low = stream.read::(15).unwrap(); 33 | let _marker_bit = stream.read_bit().unwrap(); 34 | 35 | seamless_splice = Some( 36 | ((splice_type as u64) << 33) + 37 | ((dts_high as u64) << 30) + 38 | ((dts_medium as u64) << 15) + 39 | dts_low as u64 40 | ); 41 | *count += 5; 42 | } 43 | 44 | Some(AdaptationFieldExtension{ 45 | legal_time_window: legal_time_window, 46 | piecewise_rate: piecewise_rate, 47 | seamless_splice: seamless_splice, 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /src/parser/stream_id.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::stream_id::*; 3 | 4 | pub fn get_stream_id(stream_id: u8) -> StreamId { 5 | match stream_id { 6 | 0x00 => StreamId::Reserved, 7 | 0x01 => StreamId::IsoIec_11172_2_Mpeg1_Video, 8 | 0x02 => StreamId::IsoIec_13818_2_Mpeg2_Video, 9 | 0x03 => StreamId::IsoIec_11172_3_Mpeg1_Audio, 10 | 0x04 => StreamId::IsoIec_13818_3_Mpeg2_Audio, 11 | 0x05 => StreamId::IsoIec_13818_1_PrivateSection, 12 | 0x06 => StreamId::IsoIec_13818_1_Pes, 13 | 0x07 => StreamId::IsoIec_13522_Mheg, 14 | 0x08 => StreamId::Itu_T_H222_0_Annex_A_Dsm_Cc, 15 | 0x09 => StreamId::Itu_T_H222_1, 16 | 0x0a => StreamId::IsoIec_13818_6_Dsm_Cc_Type_A, 17 | 0x0b => StreamId::IsoIec_13818_6_Dsm_Cc_Type_B, 18 | 0x0c => StreamId::IsoIec_13818_6_Dsm_Cc_Type_C, 19 | 0x0d => StreamId::IsoIec_13818_6_Dsm_Cc_Type_D, 20 | 0x0e => StreamId::IsoIec_13818_1_Auxiliary, 21 | 0x0f => StreamId::IsoIec_13818_7_AAC_Audio, 22 | 0x10 => StreamId::IsoIec_14496_2_Mpeg4_Video, 23 | 0x11 => StreamId::IsoIec_14496_3_AAC_Latm_Audio, 24 | 0x1b => StreamId::Itu_T_H264_Video, 25 | 0x24 => StreamId::Itu_T_H265_Video, 26 | 0xea => StreamId::Vc1_Video, 27 | 0xd1 => StreamId::Dirac_Video, 28 | 0x81 => StreamId::Ac3_Audio, 29 | 0x8a => StreamId::Dts_Audio, 30 | 0xbd => StreamId::NonMpegAudioSubpictures, 31 | 0xbe => StreamId::PaddingStream, 32 | 0xbf => StreamId::NavigationData, 33 | _ => { 34 | if (stream_id >= 0xc0) && (stream_id <= 0xdf) { 35 | StreamId::AudioStream{id: stream_id} 36 | } else { 37 | if (stream_id >= 0xe0) && (stream_id <= 0xef) { 38 | StreamId::VideoStream{id: stream_id} 39 | } else { 40 | println!("Unknown Stream ID {:?}", stream_id); 41 | StreamId::Unknown 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/pcr_measure.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate mpegts; 3 | 4 | use std::io::BufReader; 5 | use std::fs::File; 6 | use std::process; 7 | use std::env; 8 | 9 | use mpegts::parser::packet::parse_next_packets; 10 | use mpegts::writer::continuity_pcr::ContinuityPcr; 11 | 12 | const TS_PACKET_SIZE: usize = 188; 13 | const SYSTEM_CLOCK_FREQUENCY: usize = 27000000; 14 | 15 | fn main() { 16 | 17 | if env::args().count() != 2 { 18 | println!("ERROR: missing filepath argument."); 19 | println!("usage:"); 20 | println!(" pcr_measure [filepath.ts]"); 21 | process::exit(0x0f00); 22 | } 23 | 24 | let path = env::args().last().unwrap(); 25 | 26 | let file = File::open(path).unwrap(); 27 | let mut stream = BufReader::new(file); 28 | 29 | let mut ts_packet_count = 0; 30 | 31 | let mut continuity_pcr = ContinuityPcr{streams: vec![]}; 32 | 33 | loop { 34 | let packets = parse_next_packets(&mut stream).unwrap(); 35 | 36 | for packet in packets { 37 | if packet.program_id == 0 { 38 | continue; 39 | } 40 | if packet.adaptation_field.is_some() { 41 | let af = packet.adaptation_field.unwrap(); 42 | if af.pcr.is_some() { 43 | let pcr = af.pcr.unwrap(); 44 | 45 | let new_pcr = pcr.get(); 46 | let new_pcr_index = (ts_packet_count * TS_PACKET_SIZE) + 10; 47 | 48 | match continuity_pcr.get(packet.program_id) { 49 | None => {}, 50 | Some(pcr_stream) => { 51 | let instant_bitrate = ((new_pcr_index as i64 - pcr_stream.index as i64) * 8 * SYSTEM_CLOCK_FREQUENCY as i64) as f64 / (new_pcr as i64 - pcr_stream.pcr as i64) as f64; 52 | 53 | println!("{} bitrate = {:?}", packet.program_id, instant_bitrate as i64); 54 | }, 55 | } 56 | 57 | continuity_pcr.update(packet.program_id, new_pcr, new_pcr_index); 58 | } 59 | } 60 | 61 | ts_packet_count += 1; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/writer/stream_id.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::stream_id::*; 3 | 4 | pub fn get_stream_id(stream_id: StreamId) -> u8 { 5 | match stream_id { 6 | StreamId::Reserved => 0x00, 7 | StreamId::IsoIec_11172_2_Mpeg1_Video => 0x01, 8 | StreamId::IsoIec_13818_2_Mpeg2_Video => 0x02, 9 | StreamId::IsoIec_11172_3_Mpeg1_Audio => 0x03, 10 | StreamId::IsoIec_13818_3_Mpeg2_Audio => 0x04, 11 | StreamId::IsoIec_13818_1_PrivateSection => 0x05, 12 | StreamId::IsoIec_13818_1_Pes => 0x06, 13 | StreamId::IsoIec_13522_Mheg => 0x07, 14 | StreamId::Itu_T_H222_0_Annex_A_Dsm_Cc => 0x08, 15 | StreamId::Itu_T_H222_1 => 0x09, 16 | StreamId::IsoIec_13818_6_Dsm_Cc_Type_A => 0x0a, 17 | StreamId::IsoIec_13818_6_Dsm_Cc_Type_B => 0x0b, 18 | StreamId::IsoIec_13818_6_Dsm_Cc_Type_C => 0x0c, 19 | StreamId::IsoIec_13818_6_Dsm_Cc_Type_D => 0x0d, 20 | StreamId::IsoIec_13818_1_Auxiliary => 0x0e, 21 | StreamId::IsoIec_13818_7_AAC_Audio => 0x0f, 22 | StreamId::IsoIec_14496_2_Mpeg4_Video => 0x10, 23 | StreamId::IsoIec_14496_3_AAC_Latm_Audio => 0x11, 24 | StreamId::Itu_T_H264_Video => 0x1b, 25 | StreamId::Itu_T_H265_Video => 0x24, 26 | StreamId::Vc1_Video => 0xea, 27 | StreamId::Dirac_Video => 0xd1, 28 | StreamId::Ac3_Audio => 0x81, 29 | StreamId::Dts_Audio => 0x8a, 30 | StreamId::NonMpegAudioSubpictures => 0xbd, 31 | StreamId::PaddingStream => 0xbe, 32 | StreamId::NavigationData => 0xbf, 33 | StreamId::VideoStream{id} => id, 34 | StreamId::AudioStream{id} => id, 35 | _ => unimplemented!() 36 | // { 37 | // if (stream_id >= 0xc0) && (stream_id <= 0xdf) { 38 | // StreamId::AudioStream 39 | // } else { 40 | // if (stream_id >= 0xe0) && (stream_id <= 0xef) { 41 | // StreamId::VideoStream 42 | // } else { 43 | // println!("Unknown Stream ID {:?}", stream_id); 44 | // StreamId::Unknown 45 | // } 46 | // } 47 | // } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/writer/adaptation_field_extension.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitWriter}; 3 | use mpegts::adaptation_field_extension::AdaptationFieldExtension; 4 | 5 | pub fn write(afe: &AdaptationFieldExtension) -> Vec { 6 | let mut data = Vec::new(); 7 | { 8 | let mut afe_writer = BitWriter::::new(&mut data); 9 | afe_writer.write_bit(afe.legal_time_window.is_some()).unwrap(); 10 | afe_writer.write_bit(afe.piecewise_rate.is_some()).unwrap(); 11 | afe_writer.write_bit(afe.seamless_splice.is_some()).unwrap(); 12 | 13 | match afe.legal_time_window { 14 | None => {}, 15 | Some(ref legal_time_window) => { 16 | afe_writer.write(16, *legal_time_window).unwrap(); 17 | } 18 | } 19 | match afe.piecewise_rate { 20 | None => {}, 21 | Some(ref piecewise_rate) => { 22 | afe_writer.write(24, *piecewise_rate).unwrap(); 23 | } 24 | } 25 | match afe.seamless_splice { 26 | None => {}, 27 | Some(ref seamless_splice) => { 28 | afe_writer.write(4, (*seamless_splice & (0xF << 33)) >> 33).unwrap(); 29 | afe_writer.write(3, (*seamless_splice & (0b111 << 30)) >> 30).unwrap(); 30 | afe_writer.write_bit(true).unwrap(); 31 | afe_writer.write(15, (*seamless_splice & (0x7FFF << 15)) >> 15).unwrap(); 32 | afe_writer.write_bit(true).unwrap(); 33 | afe_writer.write(15, *seamless_splice & 0x7FFF).unwrap(); 34 | afe_writer.write_bit(true).unwrap(); 35 | } 36 | } 37 | } 38 | data 39 | } 40 | 41 | pub fn write_adaptation_field_extension(writer: &mut BitWriter, adaptation_field_extension: &Option) { 42 | 43 | match *adaptation_field_extension { 44 | None => {}, 45 | Some(ref afe) => { 46 | let data = write(afe); 47 | println!("AFE len = {:?}", data.len()); 48 | writer.write(8, data.len() as u8).unwrap(); 49 | writer.write_bytes(&data).unwrap(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/mpegts/packet.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt; 3 | 4 | use mpegts::adaptation_field::AdaptationField; 5 | use mpegts::payload::Payload; 6 | use mpegts::program_association::*; 7 | use mpegts::program_map::*; 8 | 9 | #[derive(Debug, Clone)] 10 | pub struct Packet { 11 | pub transport_error_indicator: bool, 12 | pub transport_priority: bool, 13 | pub program_id: u16, 14 | pub transport_scrambling_control: u8, 15 | pub continuity_counter: u8, 16 | pub payload_presence: bool, 17 | pub adaptation_field: Option, 18 | pub payload: Option, 19 | pub data: Vec, 20 | } 21 | 22 | impl fmt::Display for Packet { 23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 24 | if self.data.len() > 0 { 25 | write!(f, "Packet with PID: {:04} (data size = {}), payload {:?}", self.program_id, self.data.len(), self.payload) 26 | } else { 27 | // write!(f, "PID: {:04}", self.program_id) 28 | write!(f, "Packet: {:?}", self) 29 | } 30 | } 31 | } 32 | 33 | impl Packet { 34 | pub fn new() -> Packet { 35 | Packet { 36 | transport_error_indicator: false, 37 | transport_priority: false, 38 | program_id: 0, 39 | transport_scrambling_control: 0x00, 40 | continuity_counter: 0x00, 41 | payload_presence: false, 42 | adaptation_field: None, 43 | payload: None, 44 | data: vec![], 45 | } 46 | } 47 | 48 | pub fn new_pat(pat: ProgramAssociation) -> Packet { 49 | let mut p = Packet::new(); 50 | p.payload_presence = true; 51 | p.payload = Some( 52 | Payload{ 53 | pat: Some(pat), 54 | pmt: None, 55 | pes: None, 56 | }); 57 | 58 | p 59 | } 60 | 61 | pub fn new_pmt(id: u16, pmt: ProgramMap) -> Packet { 62 | let mut p = Packet::new(); 63 | p.program_id = id; 64 | p.payload_presence = true; 65 | p.payload = Some( 66 | Payload{ 67 | pat: None, 68 | pmt: Some(pmt), 69 | pes: None, 70 | }); 71 | 72 | p 73 | } 74 | 75 | pub fn new_null() -> Packet { 76 | let mut p = Packet::new(); 77 | p.program_id = 0x1FFF; 78 | p 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/mpegts/stream_type.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug)] 3 | pub enum StreamType { 4 | Reserved, 5 | VideoStreamHeaderParametersForItuTRecH262IsoIec138182AndIsoIec111722, 6 | AudioStreamHeaderParametersForIsoIec138183AndIsoIec111723, 7 | HierarchyForStreamSelection, 8 | RegistrationOfPrivateFormats, 9 | DataStreamAlignmentForPacketizedVideoAndAudioSyncPoint, 10 | TargetBackgroundGridDefinesTotalDisplayAreaSize, 11 | VideoWindowDefinesPositionInDisplayArea, 12 | ConditionalAccessSystemAndEmmEcmPid, 13 | Iso639LanguageAndAudioType, 14 | SystemClockExternalReference, 15 | MultiplexBufferUtilizationBounds, 16 | CopyrightIdentificationSystemAndReference, 17 | MaximumBitRate, 18 | PrivateDataIndicator, 19 | SmoothingBuffer, 20 | StdVideoBufferLeakControl, 21 | IbpVideoIFrameIndicator, 22 | IsiIec138186DsmCcCarouselIdentifier, 23 | IsiIec138186DsmCcAssociationTag, 24 | IsiIec138186DsmCcDeferredAssociationTag, 25 | IsiIec138186DsmCcReserved, 26 | DsmCcNptReference, 27 | DsmCcNptEndpoint, 28 | DsmCcStreamMode, 29 | DsmCcStreamEvent, 30 | VideoStreamHeaderParametersForIsoIec144962, 31 | AudioStreamHeaderParametersForIsoIec144963, 32 | IodParametersForIsoIec144961, 33 | SlParametersForIsoIec144961, 34 | FmcParametersForIsoIec144961, 35 | ExternalEsIdentifierForIsoIec144961, 36 | MuxCodeForIsoIec144961, 37 | FmxBufferSizeForIsoIec144961, 38 | MultiplexBufferForIsoIec144961, 39 | ContentLabelingForIsoIec144961, 40 | MetadataPointer, 41 | Metadata, 42 | MetadataStd, 43 | VideoStreamHeaderParametersForItuTRecH264AndIsoIec1449610, 44 | IsoIec1381811Ipmp, 45 | TimingAndHrdForItuTRecH264AndIsoIec1449610, 46 | AudioStreamHeaderParametersForIsoIec138187AdtsAac, 47 | FlexMuxTimingForIsoIec144961, 48 | TextStreamHeaderParametersForIsoIec14496, 49 | AudioExtensionStreamHeaderParametersForIsoIec144963, 50 | VideoAuxiliaryStreamHeaderParameters, 51 | VideoScalableStreamHeaderParameters, 52 | VideoMultiStreamHeaderParameters, 53 | VideoStreamHeaderParametersForItuTRecT802AndIsoIec154443, 54 | VideoMultiOperationPointStreamHeaderParameters, 55 | VideoStereoscopic3DStreamHeaderParametersForItuTRecH262IsoIec138182AndIsoIec111722, 56 | ProgramStereoscopic3DInformation, 57 | VideoStereoscopic3DInformation, 58 | UsedByDvb, 59 | UsedByAtsc, 60 | VideoLanFourCc, 61 | UsedByIsdb, 62 | UsedByCableLabs, 63 | Other, 64 | Forbidden, 65 | } 66 | -------------------------------------------------------------------------------- /src/writer/adaptation_field.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitWriter}; 3 | 4 | use writer::program_clock::*; 5 | use writer::adaptation_field_extension::*; 6 | use mpegts::adaptation_field::AdaptationField; 7 | 8 | pub fn write(af: &AdaptationField) -> Vec { 9 | let mut data = Vec::new(); 10 | { 11 | let mut af_writer = BitWriter::::new(&mut data); 12 | 13 | af_writer.write_bit(af.discontinuity_indicator).unwrap(); 14 | af_writer.write_bit(af.random_access_indicator).unwrap(); 15 | af_writer.write_bit(af.elementary_stream_priority_indicator).unwrap(); 16 | af_writer.write_bit(af.pcr.is_some()).unwrap(); 17 | af_writer.write_bit(af.opcr.is_some()).unwrap(); 18 | af_writer.write_bit(af.splice_countdown.is_some()).unwrap(); 19 | af_writer.write_bit(af.transport_private_data.len() > 0).unwrap(); 20 | af_writer.write_bit(af.adaptation_field_extension.is_some()).unwrap(); 21 | 22 | match af.pcr { 23 | None => {} 24 | Some(ref pcr) => { 25 | write_program_clock(&mut af_writer, pcr); 26 | } 27 | } 28 | 29 | match af.opcr { 30 | None => {} 31 | Some(ref opcr) => { 32 | write_program_clock(&mut af_writer, opcr); 33 | } 34 | } 35 | 36 | match af.splice_countdown { 37 | None => {} 38 | Some(ref splice_countdown) => { 39 | if *splice_countdown < 0 { 40 | af_writer.write(8, (- splice_countdown) as u8 + 0x80 ).unwrap(); 41 | } else { 42 | af_writer.write(8, *splice_countdown as u8).unwrap(); 43 | } 44 | } 45 | } 46 | 47 | if af.transport_private_data.len() > 0 { 48 | af_writer.write(8, af.transport_private_data.len() as u8).unwrap(); 49 | af_writer.write_bytes(&af.transport_private_data).unwrap(); 50 | } 51 | 52 | write_adaptation_field_extension(&mut af_writer, &af.adaptation_field_extension) 53 | } 54 | data 55 | } 56 | 57 | pub fn write_adaptation_field(writer: &mut BitWriter, adaptation_field: &Option) { 58 | 59 | match *adaptation_field { 60 | None => {}, 61 | Some(ref af) => { 62 | if af.length == 0 { 63 | writer.write(8, 0 as u8).unwrap(); 64 | return 65 | } 66 | 67 | let mut data = write(af); 68 | 69 | let fill_count = (af.length as usize) - data.len(); 70 | // println!("fill count {:?}", fill_count); 71 | if fill_count > 1 { 72 | for _i in 0..fill_count { 73 | data.push(0xFF); 74 | } 75 | } 76 | writer.write(8, data.len() as u8).unwrap(); 77 | writer.write_bytes(&data).unwrap(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/parser/program_descriptor.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::program_descriptor::*; 3 | 4 | pub fn get_descriptor_id(descriptor_id: u8) -> ProgramDescriptor { 5 | match descriptor_id { 6 | 00 => ProgramDescriptor::Reserved, 7 | 01 => ProgramDescriptor::Forbidden, 8 | 02 => ProgramDescriptor::Video_Stream, 9 | 03 => ProgramDescriptor::Audio_Stream, 10 | 04 => ProgramDescriptor::Hierarchy, 11 | 05 => ProgramDescriptor::Registration, 12 | 06 => ProgramDescriptor::Data_Stream_Alignment, 13 | 07 => ProgramDescriptor::Target_Background_Grid, 14 | 08 => ProgramDescriptor::Video_Window, 15 | 09 => ProgramDescriptor::CA_Descriptor, 16 | 10 => ProgramDescriptor::ISO_639_Language, 17 | 11 => ProgramDescriptor::System_Clock, 18 | 12 => ProgramDescriptor::Multiplex_Buffer_Utilization, 19 | 13 => ProgramDescriptor::Copyright, 20 | 14 => ProgramDescriptor::Maximum_Bitrate, 21 | 15 => ProgramDescriptor::Private_Data_Indicator, 22 | 16 => ProgramDescriptor::Smoothing_Buffer, 23 | 17 => ProgramDescriptor::STD, 24 | 18 => ProgramDescriptor::IBP, 25 | 26 | 27 => ProgramDescriptor::MPEG4_Video, 27 | 28 => ProgramDescriptor::MPEG4_Audio, 28 | 29 => ProgramDescriptor::IOD, 29 | 30 => ProgramDescriptor::SL, 30 | 31 => ProgramDescriptor::FMC, 31 | 32 => ProgramDescriptor::External_ES_ID, 32 | 33 => ProgramDescriptor::MuxCode, 33 | 34 => ProgramDescriptor::FmxBufferSize, 34 | 35 => ProgramDescriptor::MultiplexBuffer, 35 | 36 => ProgramDescriptor::Content_Labeling, 36 | 37 => ProgramDescriptor::Metadata_Pointer, 37 | 38 => ProgramDescriptor::Metadata, 38 | 39 => ProgramDescriptor::Metadata_STD, 39 | 40 => ProgramDescriptor::AVC_Video, 40 | 41 => ProgramDescriptor::IPMP, 41 | 42 => ProgramDescriptor::AVC_Timing_And_HRD, 42 | 43 => ProgramDescriptor::MPEG2_AAC_Audio, 43 | 44 => ProgramDescriptor::FlexMuxTiming, 44 | 45 => ProgramDescriptor::MPEG4_Text, 45 | 46 => ProgramDescriptor::MPEG4_Audio_Extension, 46 | 47 => ProgramDescriptor::Auxiliary_Video_Stream, 47 | 48 => ProgramDescriptor::SVC_Extension, 48 | 49 => ProgramDescriptor::MVC_Extension, 49 | 50 => ProgramDescriptor::J2K_Video, 50 | 51 => ProgramDescriptor::MVC_Operation_Point, 51 | 52 => ProgramDescriptor::MPEG2_Stereoscopic_Video_Format, 52 | 53 => ProgramDescriptor::Stereoscopic_Program_Info, 53 | 54 => ProgramDescriptor::Stereoscopic_Video_Info, 54 | 55 => ProgramDescriptor::Transport_Profile, 55 | 56 => ProgramDescriptor::HEVC_Video, 56 | 63 => ProgramDescriptor::Extension, 57 | _ => { 58 | if descriptor_id >= 64 { 59 | return ProgramDescriptor::UserPrivate; 60 | } 61 | 62 | if descriptor_id >= 57 { 63 | return ProgramDescriptor::Reserved; 64 | } 65 | unimplemented!(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/parser/descriptor/hevc.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitReader}; 3 | use mpegts::descriptor::hevc::*; 4 | 5 | pub fn parse_descriptor(stream: &mut BitReader) -> Hevc { 6 | let _descriptor_id = stream.read::(8).unwrap(); 7 | let _descriptor_length = stream.read::(8).unwrap(); 8 | let profile_space = stream.read::(2).unwrap(); 9 | let tier_flag = stream.read_bit().unwrap(); 10 | let profile_idc = stream.read::(5).unwrap(); 11 | let profile_compatibility_indication = stream.read::(32).unwrap(); 12 | let progressive_source_flag = stream.read_bit().unwrap(); 13 | let interlaced_source_flag = stream.read_bit().unwrap(); 14 | let non_packed_constraint_flag = stream.read_bit().unwrap(); 15 | let frame_only_constraint_flag = stream.read_bit().unwrap(); 16 | let _profile_idc_description = stream.read::(44).unwrap(); 17 | let _level_idc = stream.read::(8).unwrap(); 18 | let temporal_layer_subset_flag = stream.read_bit().unwrap(); 19 | let _hevc_still_present_flag = stream.read_bit().unwrap(); 20 | let _hevc_24hr_picture_present_flag = stream.read_bit().unwrap(); 21 | let _reserved = stream.read::(5).unwrap(); 22 | 23 | println!("HEVC descriptor"); 24 | println!("profile_space {:?}", profile_space); 25 | println!("tier_flag {:?}", tier_flag); 26 | println!("profile_idc {:?}", profile_idc); 27 | println!("profile_compatibility_indication {:b}", profile_compatibility_indication); 28 | println!("progressive_source_flag {:?}", progressive_source_flag); 29 | println!("interlaced_source_flag {:?}", interlaced_source_flag); 30 | println!("non_packed_constraint_flag {:?}", non_packed_constraint_flag); 31 | println!("frame_only_constraint_flag {:?}", frame_only_constraint_flag); 32 | println!("temporal_layer_subset_flag {:?}", temporal_layer_subset_flag); 33 | 34 | if temporal_layer_subset_flag { 35 | let _reserved = stream.read::(5).unwrap(); 36 | let temporal_id_min = stream.read::(3).unwrap(); 37 | let _reserved = stream.read::(5).unwrap(); 38 | let temporal_id_max = stream.read::(3).unwrap(); 39 | 40 | println!("temporal_id_min {:?}", temporal_id_min); 41 | println!("temporal_id_max {:?}", temporal_id_max); 42 | } 43 | 44 | Hevc{ 45 | profile_space: profile_space, 46 | // tier_flag: tier_flag, 47 | // profile_idc: profile_idc, 48 | // profile_compatibility_indication: profile_compatibility_indication, 49 | // progressive_source_flag: progressive_source_flag, 50 | // interlaced_source_flag: interlaced_source_flag, 51 | // non_packed_constraint_flag: non_packed_constraint_flag, 52 | // frame_only_constraint_flag: frame_only_constraint_flag, 53 | // profile_idc_description: profile_idc_description, 54 | // level_idc: level_idc, 55 | // temporal_layer_subset_flag: temporal_layer_subset_flag, 56 | // hevc_still_present_flag: hevc_still_present_flag, 57 | // hevc_24hr_picture_present_flag: hevc_24hr_picture_present_flag, 58 | } 59 | } -------------------------------------------------------------------------------- /src/writer/packet.rs: -------------------------------------------------------------------------------- 1 | 2 | use writer::continuity_counter::*; 3 | use writer::adaptation_field::*; 4 | use writer::payload::*; 5 | use mpegts::packet::Packet; 6 | 7 | use std::io::{Write, Seek, SeekFrom}; 8 | use bitstream_io::{BigEndian, BitWriter}; 9 | 10 | pub fn write_packets(stream: &mut W, packets: &Vec, cc: &mut ContinuityCounter) { 11 | for packet in packets { 12 | 13 | let origin_position = stream.seek(SeekFrom::Current(0)).unwrap(); 14 | 15 | write_packet(stream, packet, cc); 16 | 17 | let end_position = stream.seek(SeekFrom::Current(0)).unwrap(); 18 | 19 | if end_position - origin_position != 188 { 20 | println!("packet size = {:?}", (end_position - origin_position)); 21 | println!("{:?}", packet); 22 | } 23 | let fill_count = 188 - (end_position - origin_position); 24 | 25 | if fill_count > 0 { 26 | println!("MpegTS Writer: wrong packet (with PID {}) length {:?}", packet.program_id, end_position - origin_position); 27 | println!("{:?}", packet); 28 | for _i in 0..fill_count { 29 | let mut fill = vec![0xFF]; 30 | let _res = stream.write(&mut fill); 31 | } 32 | } 33 | } 34 | } 35 | 36 | pub fn write_packet(mut stream: &mut W, packet: &Packet, mut cc: &mut ContinuityCounter) { 37 | let mut writer = BitWriter::::new(&mut stream); 38 | 39 | let mut continuity_counter = 0; 40 | 41 | match get_stream(&mut cc, packet.program_id) { 42 | Some(counter) => { 43 | continuity_counter = counter; 44 | }, 45 | None => { 46 | cc.streams.push(Stream{ 47 | id: packet.program_id, 48 | counter: continuity_counter 49 | }) 50 | }, 51 | } 52 | 53 | // println!("Stream {} - cc {}", packet.program_id, continuity_counter); 54 | 55 | writer.write(8, 0x47).unwrap(); 56 | 57 | writer.write_bit(packet.transport_error_indicator).unwrap(); 58 | writer.write_bit(packet.payload.is_some()).unwrap(); 59 | writer.write_bit(packet.transport_priority).unwrap(); 60 | writer.write(13, packet.program_id).unwrap(); 61 | writer.write(2, packet.transport_scrambling_control).unwrap(); 62 | writer.write_bit(packet.adaptation_field.is_some()).unwrap(); 63 | writer.write_bit(packet.payload_presence).unwrap(); 64 | writer.write(4, continuity_counter).unwrap(); 65 | 66 | write_adaptation_field(&mut writer, &packet.adaptation_field); 67 | write_payload(&mut writer, &packet.payload); 68 | 69 | writer.write_bytes(&packet.data).unwrap(); 70 | } 71 | 72 | 73 | fn get_stream(cc: &mut ContinuityCounter, program_id: u16) -> Option { 74 | let mut iter = cc.streams.iter_mut(); 75 | 76 | loop { 77 | match iter.next() { 78 | Some(ref mut stream) => { 79 | if stream.id == program_id { 80 | stream.counter += 1; 81 | if stream.counter > 15 { 82 | stream.counter = 0; 83 | } 84 | return Some(stream.counter) 85 | } 86 | }, 87 | None => {return None}, 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/parser/packet.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::packet::Packet; 3 | 4 | use parser::adaptation_field::parse_adaptation_field; 5 | use parser::payload::parse_payload; 6 | 7 | use std::io::{Read, Cursor}; 8 | use bitstream_io::{BigEndian, BitReader}; 9 | 10 | pub fn parse_next_packets(stream: &mut R) -> Result, String> { 11 | let mut buffer = [0u8; 1316]; 12 | let data = stream.read_exact(&mut buffer); 13 | match data { 14 | Err(message) => { 15 | Err(message.to_string()) 16 | }, 17 | Ok(_) => { 18 | Ok(parse_some_packets(&buffer)) 19 | } 20 | } 21 | } 22 | 23 | fn parse_some_packets(packet: &[u8]) -> Vec { 24 | let mut position = 0; 25 | 26 | let mut cursor = Cursor::new(&packet); 27 | let mut reader = BitReader::::new(&mut cursor); 28 | 29 | let mut packets = vec!(); 30 | 31 | while position + 187 < packet.len() { 32 | let sync_byte = reader.read::(8).unwrap(); 33 | if sync_byte != 0x47 { 34 | panic!("MPEGTS: bad sync byte: 0x{:x} != 0x47", sync_byte); 35 | } 36 | let transport_error_indicator = reader.read_bit().unwrap(); 37 | let payload_unit_start_indicator = reader.read_bit().unwrap(); 38 | let transport_priority = reader.read_bit().unwrap(); 39 | let program_id = reader.read::(13).unwrap(); 40 | let transport_scrambling_control = reader.read::(2).unwrap(); 41 | let adaptation_field_presence = reader.read_bit().unwrap(); 42 | let payload_presence = reader.read_bit().unwrap(); 43 | let continuity_counter = reader.read::(4).unwrap(); 44 | 45 | let mut packet = Packet { 46 | transport_error_indicator: transport_error_indicator, 47 | transport_priority: transport_priority, 48 | program_id: program_id, 49 | transport_scrambling_control: transport_scrambling_control, 50 | continuity_counter: continuity_counter, 51 | payload_presence: payload_presence, 52 | adaptation_field: None, 53 | payload: None, 54 | data: vec![] 55 | }; 56 | 57 | let mut count = 0; 58 | if adaptation_field_presence { 59 | packet.adaptation_field = parse_adaptation_field(&mut reader, &mut count); 60 | } 61 | let tmp = count; 62 | if payload_unit_start_indicator { 63 | packet.payload = parse_payload(&mut reader, &mut count); 64 | } 65 | if count > 184 { 66 | println!("packet {:?}", packet); 67 | println!("readed data = {:?} // {}", count, tmp); 68 | } 69 | let data_length : usize = 184 - count as usize; 70 | 71 | if payload_presence { 72 | let mut data = vec![0; data_length]; 73 | reader.read_bytes(&mut data).unwrap(); 74 | 75 | let mut fill_data = true; 76 | for byte in data.clone() { 77 | if byte != 0xff { 78 | fill_data = false; 79 | } 80 | } 81 | if !fill_data && program_id != 8191 { 82 | packet.data = data; 83 | } 84 | } else { 85 | 86 | let mut data = vec![0; data_length]; 87 | reader.read_bytes(&mut data).unwrap(); 88 | packet.data = data; 89 | 90 | // reader.skip((data_length * 8) as u32).unwrap(); 91 | } 92 | // println!("LOAD DATA {:?}", data_length); 93 | 94 | 95 | position += 188; 96 | packets.push(packet); 97 | }; 98 | 99 | packets 100 | } 101 | -------------------------------------------------------------------------------- /src/parser/adaptation_field.rs: -------------------------------------------------------------------------------- 1 | use bitstream_io::{BigEndian, BitReader}; 2 | use mpegts::adaptation_field::AdaptationField; 3 | 4 | use parser::program_clock::parse_program_clock; 5 | use parser::adaptation_field_extension::parse_adaptation_field_extension; 6 | 7 | pub fn parse_adaptation_field(mut stream: &mut BitReader, mut count: &mut usize) -> Option { 8 | let length = stream.read::(8).unwrap(); 9 | *count = 1; 10 | // println!("adapt length {:?}", length); 11 | 12 | if length == 0 { 13 | let adaptation_field = AdaptationField { 14 | length: length, 15 | discontinuity_indicator: false, 16 | random_access_indicator: false, 17 | elementary_stream_priority_indicator: false, 18 | pcr: None, 19 | opcr: None, 20 | splice_countdown: None, 21 | transport_private_data: vec![], 22 | adaptation_field_extension: None, 23 | }; 24 | return Some(adaptation_field) 25 | } 26 | 27 | let discontinuity_indicator = stream.read_bit().unwrap(); 28 | let random_access_indicator = stream.read_bit().unwrap(); 29 | let elementary_stream_priority_indicator = stream.read_bit().unwrap(); 30 | let pcr_flag = stream.read_bit().unwrap(); 31 | let opcr_flag = stream.read_bit().unwrap(); 32 | let splicing_point_flag = stream.read_bit().unwrap(); 33 | let transport_private_data_flag = stream.read_bit().unwrap(); 34 | let adaptation_field_extension_flag = stream.read_bit().unwrap(); 35 | 36 | *count += 1; 37 | 38 | let mut pcr = None; 39 | let mut opcr = None; 40 | let mut splice_countdown = None; 41 | let mut transport_private_data = vec![]; 42 | let mut adaptation_field_extension = None; 43 | 44 | if pcr_flag { 45 | pcr = Some(parse_program_clock(&mut stream)); 46 | *count += 6; 47 | } 48 | if opcr_flag { 49 | opcr = Some(parse_program_clock(&mut stream)); 50 | *count += 6; 51 | } 52 | if splicing_point_flag { 53 | let splice_countdown_two_complement = stream.read::(8).unwrap(); 54 | 55 | splice_countdown = 56 | if splice_countdown_two_complement & 0x80 == 0x80 { 57 | Some(- ((splice_countdown_two_complement & 0x7f) as i8)) 58 | } else { 59 | Some(splice_countdown_two_complement as i8) 60 | }; 61 | 62 | *count += 1; 63 | } 64 | if transport_private_data_flag { 65 | let transport_private_data_length = stream.read::(8).unwrap(); 66 | 67 | transport_private_data = vec![0; transport_private_data_length as usize]; 68 | 69 | stream.read_bytes(&mut transport_private_data).unwrap(); 70 | *count += 1 + transport_private_data_length as usize; 71 | } 72 | if adaptation_field_extension_flag { 73 | adaptation_field_extension = parse_adaptation_field_extension(&mut stream, &mut count); 74 | } 75 | 76 | if *count < length as usize { 77 | for _i in 0..(length + 1 - *count as u8){ 78 | let data = stream.read::(8).unwrap(); 79 | if data != 0xff { 80 | panic!("some data is not parse for AdaptationField"); 81 | } 82 | *count += 1; 83 | } 84 | } 85 | 86 | let adaptation_field = AdaptationField { 87 | length: length, 88 | discontinuity_indicator: discontinuity_indicator, 89 | random_access_indicator: random_access_indicator, 90 | elementary_stream_priority_indicator: elementary_stream_priority_indicator, 91 | pcr: pcr, 92 | opcr: opcr, 93 | splice_countdown: splice_countdown, 94 | transport_private_data: transport_private_data, 95 | adaptation_field_extension: adaptation_field_extension, 96 | }; 97 | 98 | Some(adaptation_field) 99 | } 100 | -------------------------------------------------------------------------------- /src/parser/stream_type.rs: -------------------------------------------------------------------------------- 1 | 2 | use mpegts::stream_type::*; 3 | 4 | pub fn get_stream_type(stream_type: u8) -> StreamType { 5 | match stream_type { 6 | 0x00 => StreamType::Reserved, 7 | 0x01 => StreamType::Reserved, 8 | 0x02 => StreamType::VideoStreamHeaderParametersForItuTRecH262IsoIec138182AndIsoIec111722, 9 | 0x03 => StreamType::AudioStreamHeaderParametersForIsoIec138183AndIsoIec111723, 10 | 0x04 => StreamType::HierarchyForStreamSelection, 11 | 0x05 => StreamType::RegistrationOfPrivateFormats, 12 | 0x06 => StreamType::DataStreamAlignmentForPacketizedVideoAndAudioSyncPoint, 13 | 0x07 => StreamType::TargetBackgroundGridDefinesTotalDisplayAreaSize, 14 | 0x08 => StreamType::VideoWindowDefinesPositionInDisplayArea, 15 | 0x09 => StreamType::ConditionalAccessSystemAndEmmEcmPid, 16 | 0x0A => StreamType::Iso639LanguageAndAudioType, 17 | 0x0B => StreamType::SystemClockExternalReference, 18 | 0x0C => StreamType::MultiplexBufferUtilizationBounds, 19 | 0x0D => StreamType::CopyrightIdentificationSystemAndReference, 20 | 0x0E => StreamType::MaximumBitRate, 21 | 0x0F => StreamType::PrivateDataIndicator, 22 | 0x10 => StreamType::SmoothingBuffer, 23 | 0x11 => StreamType::StdVideoBufferLeakControl, 24 | 0x12 => StreamType::IbpVideoIFrameIndicator, 25 | 0x13 => StreamType::IsiIec138186DsmCcCarouselIdentifier, 26 | 0x14 => StreamType::IsiIec138186DsmCcAssociationTag, 27 | 0x15 => StreamType::IsiIec138186DsmCcDeferredAssociationTag, 28 | 0x16 => StreamType::IsiIec138186DsmCcReserved, 29 | 0x17 => StreamType::DsmCcNptReference, 30 | 0x18 => StreamType::DsmCcNptEndpoint, 31 | 0x19 => StreamType::DsmCcStreamMode, 32 | 0x1A => StreamType::DsmCcStreamEvent, 33 | 0x1B => StreamType::VideoStreamHeaderParametersForIsoIec144962, 34 | 0x1C => StreamType::AudioStreamHeaderParametersForIsoIec144963, 35 | 0x1D => StreamType::IodParametersForIsoIec144961, 36 | 0x1E => StreamType::SlParametersForIsoIec144961, 37 | 0x1F => StreamType::FmcParametersForIsoIec144961, 38 | 0x20 => StreamType::ExternalEsIdentifierForIsoIec144961, 39 | 0x21 => StreamType::MuxCodeForIsoIec144961, 40 | 0x22 => StreamType::FmxBufferSizeForIsoIec144961, 41 | 0x23 => StreamType::MultiplexBufferForIsoIec144961, 42 | 0x24 => StreamType::ContentLabelingForIsoIec144961, 43 | 0x25 => StreamType::MetadataPointer, 44 | 0x26 => StreamType::Metadata, 45 | 0x27 => StreamType::MetadataStd, 46 | 0x28 => StreamType::VideoStreamHeaderParametersForItuTRecH264AndIsoIec1449610, 47 | 0x29 => StreamType::IsoIec1381811Ipmp, 48 | 0x2A => StreamType::TimingAndHrdForItuTRecH264AndIsoIec1449610, 49 | 0x2B => StreamType::AudioStreamHeaderParametersForIsoIec138187AdtsAac, 50 | 0x2C => StreamType::FlexMuxTimingForIsoIec144961, 51 | 0x2D => StreamType::TextStreamHeaderParametersForIsoIec14496, 52 | 0x2E => StreamType::AudioExtensionStreamHeaderParametersForIsoIec144963, 53 | 0x2F => StreamType::VideoAuxiliaryStreamHeaderParameters, 54 | 0x30 => StreamType::VideoScalableStreamHeaderParameters, 55 | 0x31 => StreamType::VideoMultiStreamHeaderParameters, 56 | 0x32 => StreamType::VideoStreamHeaderParametersForItuTRecT802AndIsoIec154443, 57 | 0x33 => StreamType::VideoMultiOperationPointStreamHeaderParameters, 58 | 0x34 => StreamType::VideoStereoscopic3DStreamHeaderParametersForItuTRecH262IsoIec138182AndIsoIec111722, 59 | 0x35 => StreamType::ProgramStereoscopic3DInformation, 60 | 0x36 => StreamType::VideoStereoscopic3DInformation, 61 | 0xA0 => StreamType::VideoLanFourCc, 62 | 0xFF => StreamType::Forbidden, 63 | _ => { 64 | if (stream_type >= 0x37) && (stream_type <= 0x3F) { 65 | StreamType::Reserved 66 | } else { 67 | StreamType::Other 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/writer/payload.rs: -------------------------------------------------------------------------------- 1 | 2 | use bitstream_io::{BigEndian, BitWriter}; 3 | use crc::{crc32, Hasher32}; 4 | 5 | use mpegts::table_id::*; 6 | use mpegts::program_association::ProgramAssociation; 7 | use mpegts::program_map::ProgramMap; 8 | use mpegts::packetized_elementary_stream::PacketizedElementaryStream; 9 | use mpegts::payload::Payload; 10 | use mpegts::stream_id::StreamId; 11 | use writer::table_id::get_table_id; 12 | use writer::stream_id::get_stream_id; 13 | 14 | pub fn write_payload(writer: &mut BitWriter, payload: &Option) { 15 | match *payload { 16 | None => {}, 17 | Some(ref p) => { 18 | 19 | match p.pes { 20 | None => {}, 21 | Some(ref pes) => { 22 | writer.write(16, 0).unwrap(); 23 | writer.write(8, 1).unwrap(); 24 | writer.write(8, get_stream_id(pes.stream_id.clone())).unwrap(); 25 | 26 | let data = write_packetized_elementary_stream(&pes); 27 | 28 | match pes.stream_id { 29 | StreamId::VideoStream{id: _id} => { 30 | writer.write(16, 0).unwrap(); 31 | }, 32 | _ => { 33 | writer.write(16, data.len() as u16).unwrap(); 34 | }, 35 | } 36 | writer.write_bytes(&data).unwrap(); 37 | }, 38 | } 39 | 40 | match p.pat { 41 | None => {}, 42 | Some(ref pat) => { 43 | writer.write(8, 0).unwrap(); 44 | writer.write(8, get_table_id(TableId::ProgramAssociation)).unwrap(); 45 | writer.write_bit(true).unwrap(); 46 | writer.write_bit(false).unwrap(); 47 | writer.write(2, 0b11).unwrap(); 48 | let data = write_program_association(&pat); 49 | writer.write(12, data.len() as u16 + 4).unwrap(); 50 | writer.write_bytes(&data).unwrap(); 51 | 52 | let mut digest = crc32::Digest::new(crc32::IEEE); 53 | digest.write(&data); 54 | let crc32 = digest.sum32(); 55 | writer.write(32, crc32).unwrap(); 56 | }, 57 | } 58 | match p.pmt { 59 | None => {}, 60 | Some(ref pmt) => { 61 | writer.write(8, 0).unwrap(); 62 | writer.write(8, get_table_id(TableId::ProgramMap)).unwrap(); 63 | writer.write_bit(true).unwrap(); 64 | writer.write_bit(false).unwrap(); 65 | writer.write(2, 0b11).unwrap(); 66 | let data = write_program_map(&pmt); 67 | writer.write(12, data.len() as u16 + 4).unwrap(); 68 | writer.write_bytes(&data).unwrap(); 69 | let mut digest = crc32::Digest::new(crc32::IEEE); 70 | digest.write(&data); 71 | let crc32 = digest.sum32(); 72 | writer.write(32, crc32).unwrap(); 73 | }, 74 | } 75 | } 76 | } 77 | } 78 | 79 | fn write_program_association(pat: &ProgramAssociation) -> Vec { 80 | let mut data = Vec::new(); 81 | { 82 | let mut writer = BitWriter::::new(&mut data); 83 | writer.write(16, pat.transport_stream_id).unwrap(); 84 | writer.write(2, 0b11).unwrap(); 85 | let version_number = 0x00; 86 | writer.write(5, version_number).unwrap(); 87 | writer.write_bit(true).unwrap(); 88 | writer.write(8, 0x00).unwrap(); 89 | writer.write(8, 0x00).unwrap(); 90 | for association in &pat.table { 91 | writer.write(16, association.program_number).unwrap(); 92 | writer.write(3, 0b111).unwrap(); 93 | writer.write(13, association.program_map_pid).unwrap(); 94 | } 95 | } 96 | data 97 | } 98 | 99 | fn write_program_map(pmt: &ProgramMap) -> Vec { 100 | let mut data = Vec::new(); 101 | { 102 | let mut writer = BitWriter::::new(&mut data); 103 | writer.write(16, pmt.program_number).unwrap(); 104 | writer.write(2, 0b11).unwrap(); 105 | let version_number = 0x00; 106 | writer.write(5, version_number).unwrap(); 107 | writer.write_bit(true).unwrap(); 108 | writer.write(8, 0x00).unwrap(); 109 | writer.write(8, 0x00).unwrap(); 110 | writer.write(3, 0b111).unwrap(); 111 | writer.write(13, pmt.pcr_pid).unwrap(); 112 | writer.write(4, 0b1111).unwrap(); 113 | writer.write(12, 0x0).unwrap(); 114 | 115 | for program in &pmt.programs { 116 | writer.write(8, get_stream_id(program.stream_id.clone())).unwrap(); 117 | writer.write(3, 0b111).unwrap(); 118 | writer.write(13, program.elementary_pid).unwrap(); 119 | writer.write(4, 0b1111).unwrap(); 120 | writer.write(12, program.es_info.data.len() as u16).unwrap(); 121 | writer.write_bytes(&program.es_info.data).unwrap(); 122 | } 123 | } 124 | data 125 | } 126 | 127 | fn write_packetized_elementary_stream(pes: &PacketizedElementaryStream) -> Vec { 128 | let mut data = Vec::new(); 129 | { 130 | let mut writer = BitWriter::::new(&mut data); 131 | 132 | match pes.header { 133 | None => {}, 134 | Some(ref header) => { 135 | writer.write(2, 0b10).unwrap(); 136 | 137 | writer.write(2, header.scrambling_control).unwrap(); 138 | writer.write_bit(header.priority).unwrap(); 139 | writer.write_bit(header.data_alignment_indicator).unwrap(); 140 | writer.write_bit(header.copyright).unwrap(); 141 | writer.write_bit(header.original).unwrap(); 142 | writer.write_bit(header.pts.is_some()).unwrap(); 143 | writer.write_bit(header.dts.is_some()).unwrap(); 144 | writer.write_bit(header.escr.is_some()).unwrap(); 145 | writer.write_bit(header.es_rate.is_some()).unwrap(); 146 | writer.write_bit(header.dsm_trick_mode.is_some()).unwrap(); 147 | writer.write_bit(header.additional_copy_info.is_some()).unwrap(); 148 | writer.write_bit(header.previous_pes_packet_crc.is_some()).unwrap(); 149 | writer.write_bit(header.pes_extension.is_some()).unwrap(); 150 | writer.write(8, header.pes_header_length).unwrap(); 151 | 152 | match header.pts { 153 | None => {}, 154 | Some(ref pts) => { 155 | match header.dts { 156 | Some(_) => { 157 | writer.write(4, 0b0011).unwrap(); 158 | }, 159 | None => { 160 | writer.write(4, 0b0010).unwrap(); 161 | }, 162 | } 163 | 164 | writer.write(3, (pts & (0b111 << 30)) >> 30).unwrap(); 165 | writer.write_bit(true).unwrap(); 166 | writer.write(15, (pts & (0x7FFF << 15)) >> 15).unwrap(); 167 | writer.write_bit(true).unwrap(); 168 | writer.write(15, pts & 0x7FFF).unwrap(); 169 | writer.write_bit(true).unwrap(); 170 | } 171 | } 172 | match header.dts { 173 | None => {}, 174 | Some(ref dts) => { 175 | writer.write(4, 0b0001).unwrap(); 176 | 177 | writer.write(3, (dts & (0b111 << 30)) >> 30).unwrap(); 178 | writer.write_bit(true).unwrap(); 179 | writer.write(15, (dts & (0x7FFF << 15)) >> 15).unwrap(); 180 | writer.write_bit(true).unwrap(); 181 | writer.write(15, dts & 0x7FFF).unwrap(); 182 | writer.write_bit(true).unwrap(); 183 | } 184 | } 185 | match header.escr { 186 | None => {}, 187 | Some(ref escr) => { 188 | writer.write(3, (escr & (0b111 << 39)) >> 39).unwrap(); 189 | writer.write_bit(true).unwrap(); 190 | writer.write(15, (escr & (0x7FFF << 24)) >> 24).unwrap(); 191 | writer.write_bit(true).unwrap(); 192 | writer.write(15, (escr & (0x7FFF << 9)) >> 9).unwrap(); 193 | writer.write_bit(true).unwrap(); 194 | writer.write(9, escr & 0x1FF).unwrap(); 195 | writer.write_bit(true).unwrap(); 196 | } 197 | } 198 | match header.es_rate { 199 | None => {}, 200 | Some(ref es_rate) => { 201 | writer.write_bit(true).unwrap(); 202 | writer.write(22, es_rate & 0x3FFFFF).unwrap(); 203 | writer.write_bit(true).unwrap(); 204 | } 205 | } 206 | 207 | match header.additional_copy_info { 208 | None => {}, 209 | Some(copy_info) => { 210 | writer.write_bit(true).unwrap(); 211 | writer.write(7, copy_info).unwrap(); 212 | }, 213 | } 214 | match header.previous_pes_packet_crc { 215 | None => {}, 216 | Some(crc) => { 217 | writer.write(16, crc).unwrap(); 218 | }, 219 | } 220 | } 221 | } 222 | 223 | if pes.additional_data.len() > 0 { 224 | let _res = writer.write_bytes(&pes.additional_data); 225 | } 226 | } 227 | data 228 | } 229 | -------------------------------------------------------------------------------- /src/parser/payload.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::cmp; 3 | 4 | use std::io::Cursor; 5 | use bitstream_io::{BigEndian, BitReader}; 6 | use mpegts::payload::Payload; 7 | use mpegts::table_id::TableId; 8 | use mpegts::program_association::{ProgramAssociation, Association}; 9 | use mpegts::program_map::*; 10 | use mpegts::program_descriptor::*; 11 | // use mpegts::descriptor::hevc::*; 12 | use mpegts::packetized_elementary_stream::*; 13 | use parser::stream_id::get_stream_id; 14 | use parser::table_id::get_table_id; 15 | use parser::program_descriptor::get_descriptor_id; 16 | use parser::descriptor::hevc::*; 17 | 18 | fn parse_table(stream: &mut BitReader, count: &mut usize, length: u16) -> (u16, Vec) { 19 | let table_id_extension = stream.read::(16).unwrap(); 20 | let _reserved = stream.read::(2).unwrap(); 21 | let _version = stream.read::(5).unwrap(); 22 | let _current_next_indicator = stream.read_bit().unwrap(); 23 | let _section_number = stream.read::(8).unwrap(); 24 | let _last_section_number = stream.read::(8).unwrap(); 25 | 26 | *count += 5; 27 | let mut data = vec![0; (length - 5 - 4) as usize]; 28 | stream.read_bytes(&mut data).unwrap(); 29 | 30 | *count += data.len(); 31 | 32 | let _crc32 = stream.read::(32).unwrap(); 33 | *count += 4; 34 | (table_id_extension, data) 35 | } 36 | 37 | pub fn parse_program_association(mut stream: &mut BitReader, mut count: &mut usize, length: u16) -> ProgramAssociation { 38 | let (transport_stream_id, data) = parse_table(&mut stream, &mut count, length); 39 | 40 | let mut associations = vec![]; 41 | 42 | for i in 0..data.len() / 4 { 43 | let program_number = ((data[0 + i * 4] as u16) << 8) + data[1 + i * 4] as u16; 44 | let program_pid = ((data[2 + i * 4] as u16 & 0x001f) << 8) + data[3 + i * 4] as u16; 45 | 46 | associations.push(Association{ 47 | program_number: program_number, 48 | program_map_pid: program_pid 49 | }); 50 | } 51 | 52 | ProgramAssociation{ 53 | transport_stream_id: transport_stream_id, 54 | table: associations 55 | } 56 | } 57 | 58 | pub fn parse_program_map(mut stream: &mut BitReader, mut count: &mut usize, length: u16) -> ProgramMap { 59 | let (table_id_extension, data) = parse_table(&mut stream, &mut count, length); 60 | 61 | // println!("{:?}", data); 62 | 63 | let pcr_pid = ((data[0] as u16 & 0x001f) << 8) + data[1] as u16; 64 | let pi_length = ((data[2] as u16 & 0x0003) << 8) + data[3] as u16; 65 | 66 | if pi_length != 0 { 67 | unimplemented!(); 68 | } 69 | 70 | let mut programs = vec![]; 71 | 72 | let mut offset = 4; 73 | loop { 74 | if offset >= data.len() { 75 | break; 76 | } 77 | 78 | let stream_type = data[offset]; 79 | let elementary_pid = ((data[offset+1] as u16 & 0x001f) << 8) + data[offset+2] as u16; 80 | let es_info_length = ((data[offset+3] as u16 & 0x0003) << 8) + data[offset+4] as u16; 81 | 82 | let start = offset + 5; 83 | let end = offset + 5 + es_info_length as usize; 84 | let es_info = &data[start .. end]; 85 | 86 | let descriptor = get_descriptor_id(es_info[0]); 87 | 88 | let mut cursor = Cursor::new(&es_info); 89 | let mut es_info_reader = BitReader::::new(&mut cursor); 90 | 91 | let hevc_descriptor = 92 | match descriptor { 93 | ProgramDescriptor::HEVC_Video => Some(parse_descriptor(&mut es_info_reader)), 94 | // ProgramDescriptor::UserPrivate => Some(parse_descriptor(&mut es_info_reader)), 95 | _ => None 96 | }; 97 | 98 | println!("{:?}", get_descriptor_id(es_info[0])); 99 | 100 | offset += 5 + es_info_length as usize; 101 | 102 | programs.push(Program{ 103 | stream_id: get_stream_id(stream_type), 104 | elementary_pid: elementary_pid, 105 | es_info: EsInfo{ 106 | descriptor: descriptor, 107 | hevc: hevc_descriptor, 108 | data: es_info.to_vec() 109 | } 110 | }) 111 | } 112 | 113 | ProgramMap { 114 | program_number: table_id_extension, 115 | pcr_pid: pcr_pid, 116 | programs: programs 117 | } 118 | } 119 | 120 | pub fn parse_payload(mut stream: &mut BitReader, mut count: &mut usize) -> Option { 121 | let mut header : [u8; 3] = [0; 3]; 122 | let _ret = stream.read_bytes(&mut header); 123 | // println!("{:?}", header); 124 | *count += 3; 125 | 126 | let mut pat = None; 127 | let mut pmt = None; 128 | let mut pes = None; 129 | 130 | match (header[0], header[1], header[2]) { 131 | (0x00, 0x00, 0x01) => { 132 | let es_id = stream.read::(8).unwrap(); 133 | *count += 1; 134 | 135 | let pes_packet_length = stream.read::(16).unwrap(); 136 | *count += 2; 137 | 138 | let mut header = None; 139 | let mut additional_data = vec![]; 140 | 141 | if pes_packet_length == 0 { 142 | let optional_pes_header = stream.read::(2).unwrap(); 143 | 144 | if optional_pes_header == 0x02 { 145 | let mut pts = None; 146 | let mut dts = None; 147 | let mut escr = None; 148 | let mut es_rate = None; 149 | let mut dsm_trick_mode = None; 150 | let mut additional_copy_info = None; 151 | let mut previous_pes_packet_crc = None; 152 | let pes_extension = None; 153 | 154 | let scrambling_control = stream.read::(2).unwrap(); 155 | let priority = stream.read_bit().unwrap(); 156 | let data_alignment_indicator = stream.read_bit().unwrap(); 157 | let copyright = stream.read_bit().unwrap(); 158 | let original = stream.read_bit().unwrap(); 159 | 160 | let pts_presence = stream.read_bit().unwrap(); 161 | let dts_presence = stream.read_bit().unwrap(); 162 | let escr_flag = stream.read_bit().unwrap(); 163 | let es_rate_flag = stream.read_bit().unwrap(); 164 | let dsm_trick_mode_flag = stream.read_bit().unwrap(); 165 | let additional_copy_info_flag = stream.read_bit().unwrap(); 166 | let crc_flag = stream.read_bit().unwrap(); 167 | let extension_flag = stream.read_bit().unwrap(); 168 | let pes_header_length = stream.read::(8).unwrap(); 169 | 170 | *count += 3; 171 | 172 | if pts_presence { 173 | let _pts_tag = stream.read::(4).unwrap(); 174 | let pts_high = stream.read::(3).unwrap(); 175 | let _marker = stream.read::(1).unwrap(); 176 | let pts_middle = stream.read::(15).unwrap(); 177 | let _marker = stream.read::(1).unwrap(); 178 | let pts_low = stream.read::(15).unwrap(); 179 | let _marker = stream.read::(1).unwrap(); 180 | 181 | let pts_value = ((pts_high as u64) << 30) + 182 | ((pts_middle as u64) << 15) + 183 | ((pts_low as u64)); 184 | 185 | pts = Some(pts_value); 186 | *count += 5; 187 | } 188 | 189 | if dts_presence { 190 | let _dts_tag = stream.read::(4).unwrap(); 191 | let dts_high = stream.read::(3).unwrap(); 192 | let _marker = stream.read::(1).unwrap(); 193 | let dts_middle = stream.read::(15).unwrap(); 194 | let _marker = stream.read::(1).unwrap(); 195 | let dts_low = stream.read::(15).unwrap(); 196 | let _marker = stream.read::(1).unwrap(); 197 | let dts_value = ((dts_high as u64) << 30) + 198 | ((dts_middle as u64) << 15) + 199 | ((dts_low as u64)); 200 | dts = Some(dts_value); 201 | *count += 5; 202 | } 203 | 204 | if escr_flag { 205 | let _reserved = stream.read::(2).unwrap(); 206 | let escr_high = stream.read::(3).unwrap(); 207 | let _market_bit = stream.read_bit().unwrap(); 208 | let escr_middle = stream.read::(15).unwrap(); 209 | let _market_bit = stream.read_bit().unwrap(); 210 | let escr_low = stream.read::(15).unwrap(); 211 | let _market_bit = stream.read_bit().unwrap(); 212 | let escr_extension = stream.read::(9).unwrap(); 213 | let _market_bit = stream.read_bit().unwrap(); 214 | 215 | let escr_value = ((escr_high as u64) << 39) + 216 | ((escr_middle as u64) << 24) + 217 | ((escr_low as u64) << 9) + 218 | ((escr_extension as u64)); 219 | 220 | escr = Some(escr_value); 221 | *count += 6; 222 | } 223 | 224 | if es_rate_flag { 225 | let _market_bit = stream.read_bit().unwrap(); 226 | es_rate = Some(stream.read::(22).unwrap()); 227 | let _market_bit = stream.read_bit().unwrap(); 228 | *count += 3; 229 | } 230 | 231 | if dsm_trick_mode_flag { 232 | let mode = 233 | match stream.read::(3).unwrap() { 234 | 0b000 => TrickModeControl::FastForward, 235 | 0b001 => TrickModeControl::SlowMotion, 236 | 0b010 => TrickModeControl::FreezeFrame, 237 | 0b011 => TrickModeControl::FastReverse, 238 | 0b100 => TrickModeControl::SlowReverse, 239 | _ => TrickModeControl::Reserved, 240 | }; 241 | 242 | let info = stream.read::(5).unwrap(); 243 | 244 | dsm_trick_mode = Some(DsmTrickMode{ 245 | trick_mode_control: mode, 246 | info: info 247 | }); 248 | } 249 | if crc_flag { 250 | previous_pes_packet_crc = Some(stream.read::(16).unwrap()) 251 | } 252 | if additional_copy_info_flag { 253 | let _market_bit = stream.read_bit().unwrap(); 254 | additional_copy_info = Some(stream.read::(7).unwrap()); 255 | } 256 | if extension_flag { 257 | // let pes_private_data_flag = stream.read_bit().unwrap(); 258 | // let pack_header_field_flag = stream.read_bit().unwrap(); 259 | // let program_packet_sequence_counter_flag = stream.read_bit().unwrap(); 260 | // let p_std_buffer_flag = stream.read_bit().unwrap(); 261 | // let _reserved = stream.read::(2).unwrap(); 262 | // let pes_extension_flag_2 = stream.read_bit().unwrap(); 263 | 264 | // let mut pes_private_data = vec![]; 265 | // if pes_private_data_flag { 266 | // pes_private_data = vec![0; 16]; 267 | // stream.read_bytes(&mut pes_private_data).unwrap(); 268 | // } 269 | 270 | // if pack_header_field_flag { 271 | // let pack_header_length = stream.read::(8).unwrap(); 272 | 273 | // let mut some_data = vec![0; pack_header_length as usize]; 274 | // stream.read_bytes(&mut some_data).unwrap(); 275 | // } 276 | 277 | // pes_extension = Some(PesExtension{ 278 | // pes_private_data: pes_private_data 279 | // }); 280 | 281 | unimplemented!(); 282 | } 283 | 284 | 285 | header = Some(PesHeader{ 286 | scrambling_control: scrambling_control, 287 | priority: priority, 288 | data_alignment_indicator: data_alignment_indicator, 289 | copyright: copyright, 290 | original: original, 291 | pts: pts, 292 | dts: dts, 293 | escr: escr, 294 | es_rate: es_rate, 295 | dsm_trick_mode: dsm_trick_mode, 296 | additional_copy_info: additional_copy_info, 297 | previous_pes_packet_crc: previous_pes_packet_crc, 298 | pes_extension: pes_extension, 299 | pes_header_length: pes_header_length 300 | }); 301 | } else { 302 | let _more = stream.read::(6).unwrap(); 303 | *count += 1; 304 | } 305 | } else { 306 | unimplemented!(); 307 | } 308 | 309 | if pes_packet_length > 0 { 310 | 311 | let l = cmp::min(pes_packet_length, 184 - *count as u16); 312 | additional_data = vec![0; l as usize]; 313 | stream.read_bytes(&mut additional_data).unwrap(); 314 | 315 | *count += l as usize; 316 | } 317 | 318 | pes = Some(PacketizedElementaryStream{ 319 | stream_id: get_stream_id(es_id), 320 | header: header, 321 | additional_data: additional_data, 322 | }); 323 | }, 324 | (0xFF, _, _) => { 325 | return None 326 | }, 327 | (pointer_size, table, next) => { 328 | if pointer_size > 0x00 { 329 | println!("POINTER {}", pointer_size); 330 | return None 331 | } 332 | 333 | let mut syntax_section_length = stream.read::(8).unwrap() as u16; 334 | *count += 1; 335 | syntax_section_length += ((next & 0x03) as u16) << 8; 336 | 337 | match get_table_id(table) { 338 | TableId::ProgramAssociation => { 339 | pat = Some(parse_program_association(&mut stream, &mut count, syntax_section_length)); 340 | }, 341 | TableId::ProgramMap => { 342 | pmt = Some(parse_program_map(&mut stream, &mut count, syntax_section_length)); 343 | }, 344 | _ => {} 345 | } 346 | }, 347 | } 348 | 349 | Some(Payload{ 350 | pat: pat, 351 | pmt: pmt, 352 | pes: pes 353 | }) 354 | } 355 | --------------------------------------------------------------------------------