Rtmp协议看一篇就够了_fdsafwagdagadg6576的专栏-CSDN博客
rtmp 封装h264需要应用层处理, librtmp仅仅负责connect&send
本例实现rtp 流转成rtmp流
rtmp 协议封包
Rtmp协议看一篇就够了_fdsafwagdagadg6576的专栏-CSDN博客
实现代码
audio
video
videoheader:
//videoTagHeader packetBody[iter++] = 0x17; // 1:keyframe 7:AVC packetBody[iter++] = 0x00; // AVC sequence header packetBody[iter++] = 0x00; packetBody[iter++] = 0x00; packetBody[iter++] = 0x00; // fill in 0; packetBody[iter++] = 0x01; unsigned int nal_len = 0 ; unsigned char * buf_offset = m_videoHeader->m_SPS->m_pData; unsigned char * buf = buf_offset ; int total = m_videoHeader->m_SPS->m_iLen ; unsigned char *nal = NULL ; //videoTagBody nal = get_nal1( &nal_len, &buf_offset, buf, total, p->static_inaluHeaderLen ) ; { VideoCtlData * pItem = m_videoHeader->m_SPS ; if ( pItem->m_iLen >= 4 ) { packetBody[iter++] = nal[1] ; packetBody[iter++] = nal[2] ; packetBody[iter++] = nal[3] ; } } packetBody[iter++] = 0xFF ; packetBody[iter++] = 0xE0 | ( 0x1F & m_videoHeader->m_iSPSNumber ) ; if ( m_videoHeader->m_SPS != NULL ) { packetBody[iter++] = nal_len >> 8 ; packetBody[iter++] = nal_len & 0xFF ; memcpy( &packetBody[iter], nal, nal_len ) ; iter += nal_len ; } packetBody[iter++] = m_videoHeader->m_iPPSNumber ; //PPS Header if ( m_videoHeader->m_PPS != NULL ) { packetBody[iter++] = ( m_videoHeader->m_PPS->m_iLen - p->static_inaluHeaderLen ) >> 8 ; packetBody[iter++] = ( m_videoHeader->m_PPS->m_iLen - p->static_inaluHeaderLen ) & 0xFF ; memcpy( &packetBody[iter], m_videoHeader->m_PPS->m_pData + p->static_inaluHeaderLen, m_videoHeader->m_PPS->m_iLen - p->static_inaluHeaderLen ) ; iter += m_videoHeader->m_PPS->m_iLen - p->static_inaluHeaderLen ; }
videodata
int _send_video_data_toserver( janus_videoroom_participant *p, PushItemData *videoItem ) { int ibegain = ( DATA_HEADER_SIZE - 5 ) ; //0x00000001+type is 5 byte //tag data第一个字节0x17固定 unsigned char *packetBody = videoItem->m_dataPtr + ibegain; int iter = 0 ; if ( videoItem->m_bKeyFrame ) { packetBody[iter++] = 0x17; } else { packetBody[iter++] = 0x27 ; } ..... AssembleNaluData( p, videoItem->m_dataPtr + DATA_HEADER_SIZE, videoItem->m_dwSize ) ; iRet = _send_Rtmp_packet(...); } //VideoTagBody gboolean AssembleNaluData( janus_videoroom_participant *p, unsigned char *pNaluData, int iLen ) { while( ( nal = get_nal1( &nal_len, &buf_offset, buf, total, p->static_inaluHeaderLen ) ) != NULL ) { offset = write_nal_len; //nal len +nal data pNaluData[offset++] = ( uint8_t )( ( nal_len >> 24 ) & 0x7f ); //nal length pNaluData[offset++] = ( uint8_t )( ( nal_len >> 16 ) & 0xff ); //nal length pNaluData[offset++] = ( uint8_t )( ( nal_len >> 8 ) & 0xff ); //nal length pNaluData[offset++] = ( uint8_t )( nal_len & 0xff ); //nal length write_nal_len += nal_len + p->static_inaluHeaderLen ; } }
发送
//调用librtmp发送 int _send_Rtmp_packet( janus_videoroom_participant *p, unsigned int packetType, unsigned char *data, unsigned int size, uint32_t nTimeStamp ) { guint64 janus_session_id = 0; //一个RTMPPacket对应RTMP协议规范里面的一个块(Chunk) RTMPPacket packet; RTMPPacket_Reset( &packet ); /* Chunk Basic Header: HeaderType+ChannelID组成 1个字节 * >HeaderType(前两bit): 00->12字节 01->8字节 * >ChannelID(后6个bit): 02->Ping和ByteRead通道 03->Invoke通道 connect() publish()和自己写的NetConnection.Call() 04->Audio和Vidio通道 * 12字节举例 * Chunk Message Header: timestamp + message_length+message_typ + msg_stream_id */ //rtmp chunk header; packet.m_packetType = packetType; packet.m_nChannel = 0x04; //audio or video packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_nTimeStamp = nTimeStamp; packet.m_nInfoField2 = p->m_pub_rtmp.m_stream_id ; packet.m_nBodySize = size; packet.m_body = ( char* )( data + RTMP_MAX_HEADER_SIZE ) ; //librtmp send interface; 应该是librtmp自动添加了basic header,messge handle etc int iRet = RTMP_SendPacket( &p->m_pub_rtmp, &packet, 0 ) ; .... }