diff options
author | Sho Amano <samano@xevo.com> | 2017-08-29 14:26:26 +0900 |
---|---|---|
committer | Sho Amano <samano@xevo.com> | 2017-08-29 17:25:06 +0900 |
commit | 2b3e382b4098d2a2578805a7eccc670b0f86ba26 (patch) | |
tree | a833d0073ebdd82e8654af3ef0bc3ef6fa575364 | |
parent | b934ad91e4ebe69b8c70d8691c0381e7b77fe1e3 (diff) | |
download | sdl_ios-2b3e382b4098d2a2578805a7eccc670b0f86ba26.tar.gz |
Add dedicated methods for creating RTP frames
Reflecting code review comment.
-rw-r--r-- | SmartDeviceLink/SDLRTPH264Packetizer.m | 149 |
1 files changed, 97 insertions, 52 deletions
diff --git a/SmartDeviceLink/SDLRTPH264Packetizer.m b/SmartDeviceLink/SDLRTPH264Packetizer.m index 2f0de4877..266176bdf 100644 --- a/SmartDeviceLink/SDLRTPH264Packetizer.m +++ b/SmartDeviceLink/SDLRTPH264Packetizer.m @@ -91,71 +91,116 @@ NS_ASSUME_NONNULL_BEGIN for (NSUInteger i = 0; i < nalUnitsCount; i++) { NSData *nalUnit = nalUnits[i]; - NSUInteger nalUnitLength = nalUnit.length; BOOL isLast = ((i + 1) == nalUnitsCount); - if (RTPHeaderLen + nalUnitLength > MaxRTPPacketSize) { + if (RTPHeaderLen + nalUnit.length > MaxRTPPacketSize) { // Split into multiple Fragmentation Units ([5.8] in RFC 6184) - UInt8 firstByte; - [nalUnit getBytes:&firstByte length:1]; - BOOL isFirstFragment = YES; - BOOL isLastFragment = NO; - NSUInteger offset = 1; // we have already read the first byte - - while (offset < nalUnitLength) { - NSUInteger payloadLength = MaxRTPPacketSize - (RTPHeaderLen + FragmentationUnitIndicatorLen + FragmentationUnitHeaderLen); - if (nalUnitLength - offset <= payloadLength) { - payloadLength = nalUnitLength - offset; - isLastFragment = YES; - } - NSUInteger packetSize = RTPHeaderLen + FragmentationUnitIndicatorLen + FragmentationUnitHeaderLen + payloadLength; - NSUInteger frameSize = FrameLengthLen + packetSize; - - UInt8 *buffer = malloc(frameSize); - if (buffer == NULL) { - SDLLogE(@"malloc() error"); - return nil; - } - UInt8 *p = buffer; - - p += [self sdl_writeFrameHeader:p packetSize:packetSize]; - p += [self sdl_writeRTPHeader:p marker:isLast presentationTimestamp:presentationTimestamp]; - - // Fragmentation Unit indicator - *p++ = (firstByte & 0xE0) | FragmentationUnitVersionA; - // Fragmentation Unit header - *p++ = (isFirstFragment ? 0x80 : isLastFragment ? 0x40 : 0) | (firstByte & 0x1F); - // Fragmentation Unit payload - [nalUnit getBytes:p range:NSMakeRange(offset, payloadLength)]; - offset += payloadLength; - - NSData *rtpFrame = [NSData dataWithBytesNoCopy:buffer length:frameSize]; - [rtpFrames addObject:rtpFrame]; - - isFirstFragment = NO; + if (![self sdl_addRTPFramesWithFragmentationUnits:rtpFrames nalUnit:nalUnit presentationTimestamp:presentationTimestamp isLast:isLast]) { + return nil; } } else { // Use Single NAL Unit Packet ([5.6] in RFC 6184) - NSUInteger packetSize = RTPHeaderLen + nalUnitLength; - NSUInteger frameSize = FrameLengthLen + packetSize; - - UInt8 *buffer = malloc(frameSize); - if (buffer == NULL) { - SDLLogE(@"malloc() error"); + if (![self sdl_addRTPFrameWithSingleNALUnit:rtpFrames nalUnit:nalUnit presentationTimestamp:presentationTimestamp isLast:isLast]) { return nil; } - UInt8 *p = buffer; + } + } + + return rtpFrames; +} + +/** + * Create and add a RTP frame from a NAL unit without splitting + * + * @param rtpFrames the array to which created RTP frame is added + * @param nalUnit NAL unit to create RTP frame from + * @param presentationTimestamp presentation timestamp in seconds + * @param isLast mark YES if this is the last NAL unit of a video frame + * + * @return YES if successful, NO if memory error occurred + */ +- (BOOL)sdl_addRTPFrameWithSingleNALUnit:(NSMutableArray<NSData *> *)rtpFrames + nalUnit:(NSData *)nalUnit + presentationTimestamp:(double)presentationTimestamp + isLast:(BOOL)isLast { + NSUInteger nalUnitLength = nalUnit.length; + NSUInteger packetSize = RTPHeaderLen + nalUnitLength; + NSUInteger frameSize = FrameLengthLen + packetSize; + + NSAssert(RTPHeaderLen + nalUnitLength <= MaxRTPPacketSize, @"This NAL unit doesn't fit into single RTP packet"); + + UInt8 *buffer = malloc(frameSize); + if (buffer == NULL) { + SDLLogE(@"malloc() error"); + return NO; + } + UInt8 *writePointer = buffer; + + writePointer += [self sdl_writeFrameHeader:writePointer packetSize:packetSize]; + writePointer += [self sdl_writeRTPHeader:writePointer marker:isLast presentationTimestamp:presentationTimestamp]; + [nalUnit getBytes:writePointer length:nalUnitLength]; - p += [self sdl_writeFrameHeader:p packetSize:packetSize]; - p += [self sdl_writeRTPHeader:p marker:isLast presentationTimestamp:presentationTimestamp]; - [nalUnit getBytes:p length:nalUnitLength]; + NSData *rtpFrame = [NSData dataWithBytesNoCopy:buffer length:frameSize]; + [rtpFrames addObject:rtpFrame]; - NSData *rtpFrame = [NSData dataWithBytesNoCopy:buffer length:frameSize]; - [rtpFrames addObject:rtpFrame]; + return YES; +} + +/** + * Create and add a RTP frames by splitting a NAL unit into multiple Fragmentation Units + * + * @param rtpFrames the array to which created RTP frames are added + * @param nalUnit NAL unit to create RTP frames from + * @param presentationTimestamp presentation timestamp in seconds + * @param isLast mark YES if this is the last NAL unit of a video frame + * + * @return YES if successful, NO if memory error occurred + */ +- (BOOL)sdl_addRTPFramesWithFragmentationUnits:(NSMutableArray<NSData *> *)rtpFrames + nalUnit:(NSData *)nalUnit + presentationTimestamp:(double)presentationTimestamp + isLast:(BOOL)isLast { + UInt8 firstByte; + [nalUnit getBytes:&firstByte length:1]; + BOOL isFirstFragment = YES; + BOOL isLastFragment = NO; + NSUInteger nalUnitLength = nalUnit.length; + NSUInteger offset = 1; // we have already read the first byte + + while (offset < nalUnitLength) { + NSUInteger payloadLength = MaxRTPPacketSize - (RTPHeaderLen + FragmentationUnitIndicatorLen + FragmentationUnitHeaderLen); + if (nalUnitLength - offset <= payloadLength) { + payloadLength = nalUnitLength - offset; + isLastFragment = YES; } + NSUInteger packetSize = RTPHeaderLen + FragmentationUnitIndicatorLen + FragmentationUnitHeaderLen + payloadLength; + NSUInteger frameSize = FrameLengthLen + packetSize; + + UInt8 *buffer = malloc(frameSize); + if (buffer == NULL) { + SDLLogE(@"malloc() error"); + return NO; + } + UInt8 *writePointer = buffer; + + writePointer += [self sdl_writeFrameHeader:writePointer packetSize:packetSize]; + writePointer += [self sdl_writeRTPHeader:writePointer marker:isLast presentationTimestamp:presentationTimestamp]; + + // Fragmentation Unit indicator + *writePointer++ = (firstByte & 0xE0) | FragmentationUnitVersionA; + // Fragmentation Unit header + *writePointer++ = (isFirstFragment ? 0x80 : isLastFragment ? 0x40 : 0) | (firstByte & 0x1F); + // Fragmentation Unit payload + [nalUnit getBytes:writePointer range:NSMakeRange(offset, payloadLength)]; + offset += payloadLength; + + NSData *rtpFrame = [NSData dataWithBytesNoCopy:buffer length:frameSize]; + [rtpFrames addObject:rtpFrame]; + + isFirstFragment = NO; } - return rtpFrames; + return YES; } /** |