📄 h264.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. * * Contributor(s): * Bill May wmay@cisco.com */#include "mpeg4ip.h"#include "mp4av_h264.h"#include "mpeg4ip_bitstream.h"//#define BOUND_VERBOSE 1static uint8_t exp_golomb_bits[256] = {8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };uint32_t h264_ue (CBitstream *bs){ uint32_t bits, read; int bits_left; uint8_t coded; bool done = false; uint32_t temp; bits = 0; // we want to read 8 bits at a time - if we don't have 8 bits, // read what's left, and shift. The exp_golomb_bits calc remains the // same. while (done == false) { bits_left = bs->bits_remain(); if (bits_left < 8) { read = bs->PeekBits(bits_left) << (8 - bits_left); done = true; } else { read = bs->PeekBits(8); if (read == 0) { (void)bs->GetBits(8); bits += 8; } else { done = true; } } } coded = exp_golomb_bits[read]; temp = bs->GetBits(coded); bits += coded; // printf("ue - bits %d\n", bits); return bs->GetBits(bits + 1) - 1;}int32_t h264_se (CBitstream *bs) { uint32_t ret; ret = h264_ue(bs); if ((ret & 0x1) == 0) { ret >>= 1; int32_t temp = 0 - ret; return temp; } return (ret + 1) >> 1;}static void h264_decode_annexb( uint8_t *dst, int *dstlen, const uint8_t *src, const int srclen ){ uint8_t *dst_sav = dst; const uint8_t *end = &src[srclen]; while (src < end) { if (src < end - 3 && src[0] == 0x00 && src[1] == 0x00 && src[2] == 0x03) { *dst++ = 0x00; *dst++ = 0x00; src += 3; continue; } *dst++ = *src++; } *dstlen = dst - dst_sav;}extern "C" bool h264_is_start_code (const uint8_t *pBuf) { if (pBuf[0] == 0 && pBuf[1] == 0 && ((pBuf[2] == 1) || ((pBuf[2] == 0) && pBuf[3] == 1))) { return true; } return false;}extern "C" uint32_t h264_find_next_start_code (const uint8_t *pBuf, uint32_t bufLen){ uint32_t val, temp; uint32_t offset; offset = 0; if (pBuf[0] == 0 && pBuf[1] == 0 && ((pBuf[2] == 1) || ((pBuf[2] == 0) && pBuf[3] == 1))) { pBuf += 3; offset = 3; } val = 0xffffffff; while (offset < bufLen - 3) { val <<= 8; temp = val & 0xff000000; val &= 0x00ffffff; val |= *pBuf++; offset++; if (val == H264_START_CODE) { if (temp == 0) return offset - 4; return offset - 3; } } return 0;}extern "C" uint8_t h264_nal_unit_type (const uint8_t *buffer){ uint32_t offset; if (buffer[2] == 1) offset = 3; else offset = 4; return buffer[offset] & 0x1f;}extern "C" int h264_nal_unit_type_is_slice (const uint8_t type){ if (type >= H264_NAL_TYPE_NON_IDR_SLICE && type <= H264_NAL_TYPE_IDR_SLICE) { return true; } return false;}/* * determine if the slice we decoded is a sync point */extern "C" bool h264_slice_is_idr (h264_decode_t *dec) { if (dec->nal_unit_type != H264_NAL_TYPE_IDR_SLICE) return false; if (H264_TYPE_IS_I(dec->slice_type)) return true; if (H264_TYPE_IS_SI(dec->slice_type)) return true; return false;}extern "C" uint8_t h264_nal_ref_idc (const uint8_t *buffer){ uint32_t offset; if (buffer[2] == 1) offset = 3; else offset = 4; return (buffer[offset] >> 5) & 0x3;}static void scaling_list (uint sizeOfScalingList, CBitstream *bs){ uint lastScale = 8, nextScale = 8; uint j; for (j = 0; j < sizeOfScalingList; j++) { if (nextScale != 0) { int deltaScale = h264_se(bs); nextScale = (lastScale + deltaScale + 256) % 256; } if (nextScale == 0) { lastScale = lastScale; } else { lastScale = nextScale; } }}int h264_read_seq_info (const uint8_t *buffer, uint32_t buflen, h264_decode_t *dec){ CBitstream bs; uint32_t header; uint8_t tmp[2048]; /* Should be enough for all SPS (we have at worst 13 bytes and 496 se/ue in frext) */ int tmp_len; uint32_t dummy; if (buffer[2] == 1) header = 4; else header = 5; h264_decode_annexb( tmp, &tmp_len, buffer + header, MIN(buflen-header,2048) ); bs.init(tmp, tmp_len * 8); //bs.set_verbose(true); try { dec->profile = bs.GetBits(8); dummy = bs.GetBits(1 + 1 + 1 + 1 + 4); dec->level = bs.GetBits(8); (void)h264_ue(&bs); // seq_parameter_set_id if (dec->profile == 100 || dec->profile == 110 || dec->profile == 122 || dec->profile == 144) { dec->chroma_format_idc = h264_ue(&bs); if (dec->chroma_format_idc == 3) { dec->residual_colour_transform_flag = bs.GetBits(1); } dec->bit_depth_luma_minus8 = h264_ue(&bs); dec->bit_depth_chroma_minus8 = h264_ue(&bs); dec->qpprime_y_zero_transform_bypass_flag = bs.GetBits(1); dec->seq_scaling_matrix_present_flag = bs.GetBits(1); if (dec->seq_scaling_matrix_present_flag) { for (uint ix = 0; ix < 8; ix++) { if (bs.GetBits(1)) { scaling_list(ix < 6 ? 16 : 64, &bs); } } } } dec->log2_max_frame_num_minus4 = h264_ue(&bs); dec->pic_order_cnt_type = h264_ue(&bs); if (dec->pic_order_cnt_type == 0) { dec->log2_max_pic_order_cnt_lsb_minus4 = h264_ue(&bs); } else if (dec->pic_order_cnt_type == 1) { dec->delta_pic_order_always_zero_flag = bs.GetBits(1); dec->offset_for_non_ref_pic = h264_se(&bs); // offset_for_non_ref_pic dec->offset_for_top_to_bottom_field = h264_se(&bs); // offset_for_top_to_bottom_field dec->pic_order_cnt_cycle_length = h264_ue(&bs); // poc_cycle_length for (uint32_t ix = 0; ix < dec->pic_order_cnt_cycle_length; ix++) { dec->offset_for_ref_frame[MIN(ix,255)] = h264_se(&bs); // offset for ref fram - } } dummy = h264_ue(&bs); // num_ref_frames dummy = bs.GetBits(1); // gaps_in_frame_num_value_allowed_flag uint32_t PicWidthInMbs = h264_ue(&bs) + 1; dec->pic_width = PicWidthInMbs * 16; uint32_t PicHeightInMapUnits = h264_ue(&bs) + 1; dec->frame_mbs_only_flag = bs.GetBits(1); dec->pic_height = (2 - dec->frame_mbs_only_flag) * PicHeightInMapUnits * 16;#if 0 if (!dec->frame_mbs_only_flag) { printf(" mb_adaptive_frame_field_flag: %u\n", bs->GetBits(1)); } printf(" direct_8x8_inference_flag: %u\n", bs->GetBits(1)); temp = bs->GetBits(1); printf(" frame_cropping_flag: %u\n", temp); if (temp) { printf(" frame_crop_left_offset: %u\n", h264_ue(bs)); printf(" frame_crop_right_offset: %u\n", h264_ue(bs)); printf(" frame_crop_top_offset: %u\n", h264_ue(bs)); printf(" frame_crop_bottom_offset: %u\n", h264_ue(bs)); } temp = bs->GetBits(1); printf(" vui_parameters_present_flag: %u\n", temp); if (temp) { h264_vui_parameters(bs); }#endif } catch (...) { return -1; } return 0;}extern "C" int h264_find_slice_type (const uint8_t *buffer, uint32_t buflen, uint8_t *slice_type, bool noheader){ uint32_t header; uint32_t dummy; if (noheader) header = 1; else { if (buffer[2] == 1) header = 4; else header = 5; } CBitstream bs; bs.init(buffer + header, (buflen - header) * 8); try { dummy = h264_ue(&bs); // first_mb_in_slice *slice_type = h264_ue(&bs); // slice type } catch (...) { return -1; } return 0;}int h264_read_slice_info (const uint8_t *buffer, uint32_t buflen, h264_decode_t *dec){ uint32_t header; uint8_t tmp[512]; /* Enough for the begining of the slice header */ int tmp_len; uint32_t temp; if (buffer[2] == 1) header = 4; else header = 5; CBitstream bs; h264_decode_annexb( tmp, &tmp_len, buffer + header, MIN(buflen-header,512) ); bs.init(tmp, tmp_len * 8); try { dec->field_pic_flag = 0; dec->bottom_field_flag = 0; dec->delta_pic_order_cnt[0] = 0; dec->delta_pic_order_cnt[1] = 0; temp = h264_ue(&bs); // first_mb_in_slice dec->slice_type = h264_ue(&bs); // slice type temp = h264_ue(&bs); // pic_parameter_set dec->frame_num = bs.GetBits(dec->log2_max_frame_num_minus4 + 4); if (!dec->frame_mbs_only_flag) { dec->field_pic_flag = bs.GetBits(1); if (dec->field_pic_flag) { dec->bottom_field_flag = bs.GetBits(1); } } if (dec->nal_unit_type == H264_NAL_TYPE_IDR_SLICE) { dec->idr_pic_id = h264_ue(&bs); } switch (dec->pic_order_cnt_type) { case 0: dec->pic_order_cnt_lsb = bs.GetBits(dec->log2_max_pic_order_cnt_lsb_minus4 + 4); if (dec->pic_order_present_flag && !dec->field_pic_flag) { dec->delta_pic_order_cnt_bottom = h264_se(&bs); } break; case 1: if (!dec->delta_pic_order_always_zero_flag) { dec->delta_pic_order_cnt[0] = h264_se(&bs); } if (dec->pic_order_present_flag && !dec->field_pic_flag) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -