📄 main.cpp
字号:
static uint32_t remove_03 (uint8_t *bptr, uint32_t len){ uint32_t nal_len = 0; while (nal_len + 2 < len) { if (bptr[0] == 0 && bptr[1] == 0 && bptr[2] == 3) { bptr += 2; nal_len += 2; len--; memmove(bptr, bptr + 1, len - nal_len); } else { bptr++; nal_len++; } } return len;}static const char *nal[] = { "Coded slice of non-IDR picture", // 1 "Coded slice data partition A", // 2 "Coded slice data partition B", // 3 "Coded slice data partition C", // 4 "Coded slice of an IDR picture", // 5 "SEI", // 6 "Sequence parameter set", // 7 "Picture parameter set", // 8 "Access unit delimeter", // 9 "End of Sequence", // 10 "end of stream", // 11 "filler data", // 12 "Sequence parameter set extension", // 13};static const char *nal_unit_type (uint8_t type){ if (type == 0 || type >= 24) { return "unspecified"; } if (type < 14) { return nal[type - 1]; } return "reserved";}const char *slice_type[] = { "P", "B", "I", "SP", "SI", "P", "B", "I", "SP", "SI",};void h264_slice_header (h264_decode_t *dec, CBitstream *bs){ uint32_t temp; printf(" first_mb_in_slice: %u\n", h264_ue(bs)); temp = h264_ue(bs); printf(" slice_type: %u (%s)\n", temp, temp < 10 ? slice_type[temp] : "invalid"); printf(" pic_parameter_set_id: %u\n", h264_ue(bs)); dec->frame_num = bs->GetBits(dec->log2_max_frame_num_minus4 + 4); printf(" frame_num: %u (%u bits)\n", dec->frame_num, dec->log2_max_frame_num_minus4 + 4); // these are defaults dec->field_pic_flag = 0; dec->bottom_field_flag = 0; dec->delta_pic_order_cnt[0] = 0; dec->delta_pic_order_cnt[1] = 0; if (!dec->frame_mbs_only_flag) { dec->field_pic_flag = bs->GetBits(1); printf(" field_pic_flag: %u\n", dec->field_pic_flag); if (dec->field_pic_flag) { dec->bottom_field_flag = bs->GetBits(1); printf(" bottom_field_flag: %u\n", dec->bottom_field_flag); } } if (dec->nal_unit_type == H264_NAL_TYPE_IDR_SLICE) { dec->idr_pic_id = h264_ue(bs); printf(" idr_pic_id: %u\n", dec->idr_pic_id); } switch (dec->pic_order_cnt_type) { case 0: dec->pic_order_cnt_lsb = bs->GetBits(dec->log2_max_pic_order_cnt_lsb_minus4 + 4); printf(" pic_order_cnt_lsb: %u\n", dec->pic_order_cnt_lsb); if (dec->pic_order_present_flag && !dec->field_pic_flag) { dec->delta_pic_order_cnt_bottom = h264_se(bs); printf(" delta_pic_order_cnt_bottom: %d\n", dec->delta_pic_order_cnt_bottom); } break; case 1: if (!dec->delta_pic_order_always_zero_flag) { dec->delta_pic_order_cnt[0] = h264_se(bs); printf(" delta_pic_order_cnt[0]: %d\n", dec->delta_pic_order_cnt[0]); } if (dec->pic_order_present_flag && !dec->field_pic_flag) { dec->delta_pic_order_cnt[1] = h264_se(bs); printf(" delta_pic_order_cnt[1]: %d\n", dec->delta_pic_order_cnt[1]); } break; } } void h264_slice_layer_without_partitioning (h264_decode_t *dec, CBitstream *bs){ h264_slice_header(dec, bs);}uint8_t h264_parse_nal (h264_decode_t *dec, CBitstream *bs){ uint8_t type = 0; try { if (bs->GetBits(24) == 0) bs->GetBits(8); h264_check_0s(bs, 1); dec->nal_ref_idc = bs->GetBits(2); dec->nal_unit_type = type = bs->GetBits(5); printf(" ref %u type %u %s\n", dec->nal_ref_idc, type, nal_unit_type(type)); switch (type) { case H264_NAL_TYPE_NON_IDR_SLICE: case H264_NAL_TYPE_IDR_SLICE: h264_slice_layer_without_partitioning(dec, bs); break; case H264_NAL_TYPE_SEQ_PARAM: h264_parse_sequence_parameter_set(dec, bs); break; case H264_NAL_TYPE_PIC_PARAM: h264_parse_pic_parameter_set(dec, bs); break; case H264_NAL_TYPE_SEI: h264_parse_sei(dec, bs); break; case H264_NAL_TYPE_ACCESS_UNIT: printf(" primary_pic_type: %u\n", bs->GetBits(3)); break; case H264_NAL_TYPE_SEQ_EXTENSION: h264_parse_seq_ext(dec, bs); break; } } catch (BitstreamErr_t err) { printf("\nERROR reading bitstream %s\n\n", err == BITSTREAM_PAST_END ? "read past NAL end" : "too many bits requested"); } return type;} // false if different picture, true if nal is the same picturebool compare_boundary (h264_decode_t *prev, h264_decode_t *on){ if (prev->frame_num != on->frame_num) { return false; } if (prev->field_pic_flag != on->field_pic_flag) { return false; } if (prev->nal_ref_idc != on->nal_ref_idc && (prev->nal_ref_idc == 0 || on->nal_ref_idc == 0)) { return false; } if (prev->frame_num == on->frame_num && prev->pic_order_cnt_type == on->pic_order_cnt_type) { if (prev->pic_order_cnt_type == 0) { if (prev->pic_order_cnt_lsb != on->pic_order_cnt_lsb) { return false; } if (prev->delta_pic_order_cnt_bottom != on->delta_pic_order_cnt_bottom) { return false; } } else if (prev->pic_order_cnt_type == 1) { if (prev->delta_pic_order_cnt[0] != on->delta_pic_order_cnt[0]) { return false; } if (prev->delta_pic_order_cnt[1] != on->delta_pic_order_cnt[1]) { return false; } } } if (prev->nal_unit_type == H264_NAL_TYPE_IDR_SLICE && on->nal_unit_type == H264_NAL_TYPE_IDR_SLICE) { if (prev->idr_pic_id != on->idr_pic_id) { return false; } } return true; }int main (int argc, char **argv){#define MAX_BUFFER (65536 * 4) const char* usageString = "[-version] <file-name>\n"; const char *ProgName = argv[0]; while (true) { int c = -1; int option_index = 0; static struct option long_options[] = { { "version", 0, 0, 'v' }, { NULL, 0, 0, 0 } }; c = getopt_long_only(argc, argv, "v", long_options, &option_index); if (c == -1) break; switch (c) { case '?': fprintf(stderr, "usage: %s %s", ProgName, usageString); exit(0); case 'v': fprintf(stderr, "%s - %s version %s\n", ProgName, MPEG4IP_PACKAGE, MPEG4IP_VERSION); exit(0); default: fprintf(stderr, "%s: unknown option specified, ignoring: %c\n", ProgName, c); } } /* check that we have at least one non-option argument */ if ((argc - optind) < 1) { fprintf(stderr, "usage: %s %s", ProgName, usageString); exit(1); } uint8_t buffer[MAX_BUFFER]; uint32_t buffer_on, buffer_size; uint64_t bytes = 0; FILE *m_file; h264_decode_t dec, prevdec; bool have_prevdec = false; memset(&dec, 0, sizeof(dec));#if 0 uint8_t count = 0; // this prints out the 8-bit to # of zero bit array that we use // to decode ue(v) for (uint32_t ix = 0; ix <= 255; ix++) { uint8_t ij; uint8_t bit = 0x80; for (ij = 0; (bit & ix) == 0 && ij < 8; ij++, bit >>= 1); printf("%d, ", ij); count++; if (count > 16) { printf("\n"); count = 0; } } printf("\n");#endif fprintf(stdout, "%s - %s version %s\n", ProgName, MPEG4IP_PACKAGE, MPEG4IP_VERSION); m_file = fopen(argv[optind], FOPEN_READ_BINARY); if (m_file == NULL) { fprintf(stderr, "file %s not found\n", *argv); exit(-1); } buffer_on = buffer_size = 0; while (!feof(m_file)) { bytes += buffer_on; if (buffer_on != 0) { buffer_on = buffer_size - buffer_on; memmove(buffer, &buffer[buffer_size - buffer_on], buffer_on); } buffer_size = fread(buffer + buffer_on, 1, MAX_BUFFER - buffer_on, m_file); buffer_size += buffer_on; buffer_on = 0; bool done = false; CBitstream ourbs; do { uint32_t ret; ret = h264_find_next_start_code(buffer + buffer_on, buffer_size - buffer_on); if (ret == 0) { done = true; if (buffer_on == 0) { fprintf(stderr, "couldn't find start code in buffer from 0\n"); exit(-1); } } else { // have a complete NAL from buffer_on to end if (ret > 3) { uint32_t nal_len; nal_len = remove_03(buffer + buffer_on, ret);#if 0 printf("Nal length %u start code %u bytes "U64"\n", nal_len, buffer[buffer_on + 2] == 1 ? 3 : 4, bytes + buffer_on);#else printf("Nal length %u start code %u bytes \n", nal_len, buffer[buffer_on + 2] == 1 ? 3 : 4);#endif ourbs.init(buffer + buffer_on, nal_len * 8); uint8_t type; type = h264_parse_nal(&dec, &ourbs); if (type >= 1 && type <= 5) { if (have_prevdec) { // compare the 2 bool bound; bound = compare_boundary(&prevdec, &dec); printf("Nal is %s\n", bound ? "part of last picture" : "new picture"); } memcpy(&prevdec, &dec, sizeof(dec)); have_prevdec = true; } else if (type >= 9 && type <= 11) { have_prevdec = false; // don't need to check } }#if 0 printf("buffer on "X64" "X64" %u len %u %02x %02x %02x %02x\n", bytes + buffer_on, bytes + buffer_on + ret, buffer_on, ret, buffer[buffer_on], buffer[buffer_on+1], buffer[buffer_on+2], buffer[buffer_on+3]);#endif buffer_on += ret; // buffer_on points to next code } } while (done == false); } fclose(m_file); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -