封装音视频流为RTP包来网络传输

时间:2022-05-13 19:31:00

ios没有直接得api用来封装传输rtp,但是经常有用到得接收过来得音视频数据,经过X264处理转换便可以封装为Rtp包进行直接发送。大家可以看代码:

#include "rtpsession.h"
#include "rtppacket.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"


@interface VideoRTPPack : NSObject<SocketHandlerDelegate> 
{
        RTPSession          m_RTPSession;
        
        NSMutableDictionary *dicDataBuffer;
}


@property(nonatomic, retain) NSMutableDictionary *dicDataBuffer;


- (id)initWithVideoRTP:(NSString *)hostIP onPort:(unsigned short)port;


- (void)createVideoRTP:(NSString *)host onPort:(unsigned short)port;


- (void)SendVideoPacket:(unsigned char*)videoData 
                                        Nal:(int)_nal
                                   Size:(size_t)videoDataSize 
                                   User:(unsigned long)user_id
                                FrameID:(int)video_frame_id;


- (void)resendSubPacketData:(int)frameID withSubPack:(int)packID;


- (void)closeVideoRTP;


@end



#import "VideoRTPPack.h"


@implementation VideoRTPPack


@synthesize dicDataBuffer;


- (id)initWithVideoRTP:(NSString *)hostIP onPort:(unsigned short)port
{
        if (self = [super init]) 
        {
                [self createVideoRTP:hostIP onPort:port];
                
                dicDataBuffer = [[NSMutableDictionary alloc] init];
        }
        
        return self;
}


- (void)dealloc
{
        KLC_RELEASE_SAFELY(self.dicDataBuffer)
        
        [super dealloc];
}


- (void)createVideoRTP:(NSString *)host onPort:(unsigned short)port
{
        RTPUDPv4TransmissionParams m_VideoTransparams;
        RTPSessionParams m_VideoSessionparams;
        
        m_VideoSessionparams.SetOwnTimestampUnit(1.0/10.0);
        m_VideoSessionparams.SetAcceptOwnPackets(TRUE);
        m_VideoSessionparams.SetUsePollThread(0);
        m_VideoTransparams.SetPortbase(port);
        
        int nStatus = m_RTPSession.Create(m_VideoSessionparams, &m_VideoTransparams);
        if(nStatus < 0) 
        {
                NSLog(@"create rtp faild!");
                return;
        }
        
        unsigned long ipAddress = ntohl(inet_addr([host UTF8String]));
        
        RTPIPv4Address JRTPVideoAddr(ipAddress, port);
        nStatus = m_RTPSession.AddDestination(JRTPVideoAddr);
        if(nStatus < 0) 
        {
                NSLog(@"add destination faild!");
                return;
        }
        
        m_RTPSession.SetDefaultPayloadType(96);
        m_RTPSession.SetDefaultMark(FALSE);
        m_RTPSession.SetDefaultTimestampIncrement(160);
}


- (void)SendVideoPacket:(unsigned char*)videoData 
                                        Nal:(int)_nal
                                   Size:(size_t)videoDataSize 
                                   User:(unsigned long)user_id
                                FrameID:(int)video_frame_id
{
        NSLog(@"video_frame_id = %d", video_frame_id);
        
        unsigned short length = 0;
        int subPackIndex = 1;
        int i_video_loop = 0, offset = 0, video_pack_len = 0;
        NSMutableArray *subPackArray = [[NSMutableArray alloc] init];
        
        MSQ_PACK_MID msq_pack_mid;
        strcpy(msq_pack_mid.msq_head.AppName, GAppName);
        msq_pack_mid.msq_head.sTransType  = htons(TRANSTYPE_CLIENTTOSERVER);
        msq_pack_mid.msq_head.sDataType   = htons(SENDSTREAM_VIDEO_DATATYPE);
        msq_pack_mid.msq_head.lSendID     = htonl(user_id);
        
        i_video_loop = videoDataSize / VIDEO_PACKET_SIZE;
        if ((videoDataSize % VIDEO_PACKET_SIZE) > 0) i_video_loop ++;
        
        while (videoDataSize)
        {
                VideoPacket *pVideoPacket = (VideoPacket*)msq_pack_mid.msq_data;
                
                pVideoPacket->PacketHead.TotalPackets   = i_video_loop;
                pVideoPacket->PacketHead.subpacketindex = subPackIndex;
                pVideoPacket->PacketHead.sOffset        = htons(offset);
                
                video_pack_len = (videoDataSize < VIDEO_PACKET_SIZE) ? videoDataSize:VIDEO_PACKET_SIZE;
                pVideoPacket->PacketHead.sDataLength    = htons(video_pack_len);
                videoDataSize = videoDataSize - video_pack_len;
                
                pVideoPacket->PacketHead.lFrameID       = htonl(video_frame_id);
                pVideoPacket->PacketHead.timeStart      = 0;
                pVideoPacket->PacketHead.timeEnd        = 0;
                pVideoPacket->PacketHead.s_nal          = _nal;
                
                memcpy(pVideoPacket->rawData, videoData+offset, video_pack_len);
                offset = offset + video_pack_len;
                
                length = sizeof(VideoPacketHead) + video_pack_len;
                
                msq_pack_mid.msq_head.sTCPLength = htons(length);
                msq_pack_mid.msq_head.sDataLength = msq_pack_mid.msq_head.sTCPLength;
                
                NSData *subData = [NSData dataWithBytes:(void *)&msq_pack_mid length:sizeof(MSQ_HEAD)+length];
                [subPackArray addObject:subData];
                
                m_RTPSession.SendPacket(&msq_pack_mid, sizeof(MSQ_HEAD)+length);
                
                subPackIndex ++;
        }
        
        // 把视频数据存入缓冲区
        if ([[self.dicDataBuffer allKeys] count] < 50) 
        {
                [self.dicDataBuffer setObject:subPackArray 
                                                           forKey:[NSNumber numberWithInt:video_frame_id]];
        }
        else 
        {
                [self.dicDataBuffer removeObjectForKey:[NSNumber numberWithInt:video_frame_id-51]];
                [self.dicDataBuffer setObject:subPackArray 
                                                           forKey:[NSNumber numberWithInt:video_frame_id]];
        }
        
        KLC_RELEASE_SAFELY(subPackArray)
}


- (void)resendSubPacketData:(int)frameID withSubPack:(int)packID
{
        NSArray *lostArray = (NSArray *)[self.dicDataBuffer objectForKey:[NSNumber numberWithInt:frameID]];
        NSData *lostData = [lostArray objectAtIndex:packID-1];
        
        int nStatus = m_RTPSession.SendPacket([lostData bytes], [lostData length]);
        if (nStatus == 0) NSLog(@"ReSend Packet Data Succeed!");
}


- (void)closeVideoRTP
{
        if (m_RTPSession.IsActive()) 
        {
                m_RTPSession.Destroy();
        }
}




@end