| // |
| // H264.m |
| // Dropcam |
| // |
| // Created by Loren Kirkby on 12/18/09. |
| // Copyright 2009 Dropcam. All rights reserved. |
| // |
| |
| #import "H264.h" |
| |
| uint8_t get_h264_nalu_type(NSData *packet) |
| { |
| if ([packet length] < 1) |
| return -1; |
| |
| uint8_t header[1] = {0}; |
| [packet getBytes:header length:sizeof(header)]; |
| |
| uint8_t nal_unit_type = (header[0] & 0x1F); |
| return nal_unit_type; |
| } |
| |
| BOOL isStartPacket(NSData *packet) |
| { |
| if ([packet length] < 1) |
| return NO; |
| |
| uint8_t header[1] = {0}; |
| [packet getBytes:header length:sizeof(header)]; |
| |
| uint8_t nal_unit_type = (header[0] & 0x1F); |
| return nal_unit_type == 5 || nal_unit_type == 7 || nal_unit_type == 8; |
| } |
| |
| |
| static BOOL readBit(NSData *data, int bitpos) |
| { |
| uint8_t byte = ((uint8_t*)data.bytes)[bitpos / 8]; |
| int shift = 7 - (bitpos % 8); |
| uint8_t mask = byte & (1 << shift); |
| return mask >> shift; |
| } |
| |
| static uint32_t readExpGolomb(NSData *data, int *bitpos) |
| { |
| // Section 9.1 |
| int leadingZeroBits = -1; |
| for (int b = 0; !b; leadingZeroBits++) { |
| b = readBit(data, (*bitpos)++); |
| } |
| |
| uint32_t suffix = 0; |
| for (int i = 1; i <= leadingZeroBits; i++) { |
| suffix |= readBit(data, (*bitpos)++) << (leadingZeroBits - i); |
| } |
| |
| uint32_t pow2 = (1 << leadingZeroBits); |
| return pow2 - 1 + suffix; |
| } |
| |
| H264SliceType getH264SliceType(NSData *packet) |
| { |
| if ([packet length] < 2) |
| return -1; |
| |
| // Section 7.2 |
| uint8_t naluType = get_h264_nalu_type(packet); |
| if (naluType != H264_NAL_SLICE_TYPE && naluType != H264_NAL_IDR_TYPE) { |
| return -1; |
| } |
| |
| // Section 7.3 |
| int bitpos = 8; |
| uint32_t first_mb = readExpGolomb(packet, &bitpos); (void)first_mb; |
| uint32_t slice_type = readExpGolomb(packet, &bitpos); |
| return slice_type; |
| } |