import RTSPClient from "../RTSPClient" ; import { RTPPacket } from "../util" ; import * as transform from "sdp-transform" ; import { Writable } from "stream" ; const H264_HEADER = Buffer . from ( [ 0x00 , 0x00 , 0x00 , 0x01 ] ) ; interface Details { codec : string ; mediaSource : transform . MediaDescription ; rtpChannel : number ; rtcpChannel : number ; } ; export default class H264Transport { client : RTSPClient ; stream : Writable ; rtpPackets : Buffer [ ] = [ ] ; _headerWritten : boolean = false ; constructor ( client , stream , details ) { this . client = client ; this . stream = stream ; client . on ( "data" , ( channel , data , packet ) => { if ( channel == details . rtpChannel ) { if ( this . _headerWritten ) { this . processRTPPacket ( packet ) ; } } } ) ; this . processConnectionDetails ( details ) ; } processConnectionDetails ( details ) { const fmtp = ( details . mediaSource . fmtp as any ) [ 0 ] ; if ( ! fmtp ) { return ; } const fmtpConfig = transform . parseParams ( fmtp . config ) ; const splitSpropParameterSets = fmtpConfig [ 'sprop-parameter-sets' ] . toString ( ) . split ( ',' ) ; const sps_base64 = splitSpropParameterSets [ 0 ] ; const pps_base64 = splitSpropParameterSets [ 1 ] ; const sps = new Buffer ( sps_base64 , "base64" ) ; const pps = new Buffer ( pps_base64 , "base64" ) ; this . stream . write ( H264_HEADER ) ; this . stream . write ( sps ) ; this . stream . write ( H264_HEADER ) ; this . stream . write ( pps ) ; this . _headerWritten = true ; } ; processRTPPacket ( packet ) { this . rtpPackets . push ( packet . payload ) ; if ( packet . marker == 1 ) { this . processRTPFrame ( this . rtpPackets ) ; this . rtpPackets = [ ] ; } } processRTPFrame ( rtpPackets ) { const nals = [ ] ; let partialNal = [ ] ; for ( let i = 0 ; i < rtpPackets . length ; i ++ ) { const packet = rtpPackets [ i ] ; const nal_header_f_bit = ( packet [ 0 ] >> 7 ) & 0x01 ; const nal_header_nri = ( packet [ 0 ] >> 5 ) & 0x03 ; const nal_header_type = ( packet [ 0 ] >> 0 ) & 0x1F ; if ( nal_header_type >= 1 && nal_header_type <= 23 ) { nals . push ( packet ) ; } else if ( nal_header_type == 24 ) { let ptr = 1 ; while ( ptr + 2 < ( packet . length - 1 ) ) { let size = ( packet [ ptr ] << 8 ) + ( packet [ ptr + 1 ] << 0 ) ; ptr = ptr + 2 ; nals . push ( packet . slice ( ptr , ptr + size ) ) ; ptr = ptr + size ; } } else if ( nal_header_type == 25 ) { } else if ( nal_header_type == 26 ) { } else if ( nal_header_type == 27 ) { } else if ( nal_header_type == 28 ) { const fu_header_s = ( packet [ 1 ] >> 7 ) & 0x01 ; const fu_header_e = ( packet [ 1 ] >> 6 ) & 0x01 ; const fu_header_r = ( packet [ 1 ] >> 5 ) & 0x01 ; const fu_header_type = ( packet [ 1 ] >> 0 ) & 0x1F ; if ( fu_header_s == 1 && fu_header_e == 0 ) { const reconstructed_nal_type = ( nal_header_f_bit << 7 ) + ( nal_header_nri << 5 ) + fu_header_type ; partialNal = [ ] ; partialNal . push ( reconstructed_nal_type ) ; for ( let x = 2 ; x < packet . length ; x ++ ) partialNal . push ( packet [ x ] ) ; } if ( fu_header_s == 0 && fu_header_e == 0 ) { for ( let x = 2 ; x < packet . length ; x ++ ) partialNal . push ( packet [ x ] ) ; } if ( fu_header_s == 0 && fu_header_e == 1 ) { for ( let x = 2 ; x < packet . length ; x ++ ) partialNal . push ( packet [ x ] ) ; nals . push ( Buffer . from ( partialNal ) ) ; } } else if ( nal_header_type == 29 ) { } } for ( let x = 0 ; x < nals . length ; x ++ ) { this . stream . write ( H264_HEADER ) ; this . stream . write ( nals [ x ] ) ; } } }