int h264_read_avcc(avcc_t* avcc, h264_stream_t* h, bs_t* b) { avcc->configurationVersion = h264_bs_read_u8(b); avcc->AVCProfileIndication = h264_bs_read_u8(b); avcc->profile_compatibility = h264_bs_read_u8(b); avcc->AVCLevelIndication = h264_bs_read_u8(b); /* int reserved = */ h264_bs_read_u(b, 6); // '111111'b; avcc->lengthSizeMinusOne = h264_bs_read_u(b, 2); /* int reserved = */ h264_bs_read_u(b, 3); // '111'b; avcc->numOfSequenceParameterSets = h264_bs_read_u(b, 5); avcc->sps_table = (sps_t**)calloc(avcc->numOfSequenceParameterSets, sizeof(sps_t*)); for (int i = 0; i < avcc->numOfSequenceParameterSets; i++) { int sequenceParameterSetLength = h264_bs_read_u(b, 16); int len = sequenceParameterSetLength; uint8_t* buf = (uint8_t*)malloc(len); len = h264_bs_read_bytes(b, buf, len); int rc = h264_read_nal_unit(h, buf, len); free(buf); if (h->nal->nal_unit_type != NAL_UNIT_TYPE_SPS) { continue; } // TODO report errors if (rc < 0) { continue; } avcc->sps_table[i] = h->sps; // TODO copy data? } avcc->numOfPictureParameterSets = h264_bs_read_u(b, 8); avcc->pps_table = (pps_t**)calloc(avcc->numOfSequenceParameterSets, sizeof(pps_t*)); for (int i = 0; i < avcc->numOfPictureParameterSets; i++) { int pictureParameterSetLength = h264_bs_read_u(b, 16); int len = pictureParameterSetLength; uint8_t* buf = (uint8_t*)malloc(len); len = h264_bs_read_bytes(b, buf, len); int rc = h264_read_nal_unit(h, buf, len); free(buf); if (h->nal->nal_unit_type != NAL_UNIT_TYPE_PPS) { continue; } // TODO report errors if (rc < 0) { continue; } avcc->pps_table[i] = h->pps; // TODO copy data? } if (h264_bs_overrun(b)) { return -1; } return h264_bs_pos(b); }
int main(int argc, char *argv[]) { FILE* infile; uint8_t* buf = (uint8_t*)malloc( BUFSIZE ); h264_stream_t* h = h264_new(); if (argc < 2) { h264_usage(); return EXIT_FAILURE; } int opt_verbose = 1; int opt_probe = 0; #ifdef HAVE_GETOPT_LONG int c; int long_options_index; extern char* optarg; extern int optind; while ( ( c = getopt_long( argc, argv, "o:p:hv:t", long_options, &long_options_index) ) != -1 ) { switch ( c ) { case 'o': if (h264_dbgfile == NULL) { h264_dbgfile = fopen( optarg, "wt"); } break; case 'p': opt_probe = 1; opt_verbose = 0; break; case 'v': opt_verbose = atoi( optarg ); break; case 't': h264_test(argv[optind]); return 0; case 'h': default: h264_usage( ); return 1; } } infile = fopen(argv[optind], "rb"); #else infile = fopen(argv[1], "rb"); #endif if (infile == NULL) { fprintf( stderr, "!! Error: could not open file: %s \n", strerror(errno)); exit(EXIT_FAILURE); } if (h264_dbgfile == NULL) { h264_dbgfile = stdout; } size_t rsz = 0; size_t sz = 0; int64_t off = 0; uint8_t* p = buf; int nal_start, nal_end; int nal_no = 0, ret = 0; while (1) { rsz = fread(buf + sz, 1, BUFSIZE - sz, infile); if (rsz == 0) { if (ferror(infile)) { fprintf( stderr, "!! Error: read failed: %s \n", strerror(errno)); break; } break; // if (feof(infile)) } sz += rsz; while (((ret = h264_find_nal_unit(p, sz, &nal_start, &nal_end)) > 0) || (ret == -1 && sz > 0)) { ++nal_no; if ( opt_verbose > 0 ) { fprintf( h264_dbgfile, "!! Found NAL %lld at offset %lld (0x%04llX), size %lld (0x%04llX) \n", (long long int)(nal_no), (long long int)(off + (p - buf) + nal_start), (long long int)(off + (p - buf) + nal_start), (long long int)(nal_end - nal_start), (long long int)(nal_end - nal_start) ); } p += nal_start; h264_read_nal_unit(h, p, nal_end - nal_start); if ( opt_probe && h->nal->nal_unit_type == NAL_UNIT_TYPE_SPS ) { // print codec parameter, per RFC 6381. int constraint_byte = h->sps->constraint_set0_flag << 7; constraint_byte = h->sps->constraint_set1_flag << 6; constraint_byte = h->sps->constraint_set2_flag << 5; constraint_byte = h->sps->constraint_set3_flag << 4; constraint_byte = h->sps->constraint_set4_flag << 3; constraint_byte = h->sps->constraint_set4_flag << 3; fprintf( h264_dbgfile, "codec: avc1.%02X%02X%02X\n",h->sps->profile_idc, constraint_byte, h->sps->level_idc ); // TODO: add more, move to h264_stream (?) break; // we've seen enough, bailing out. } if ( opt_verbose > 0 ) { fprintf( h264_dbgfile, "XX "); h264_debug_bytes(p-4, nal_end - nal_start + 4 >= 16 ? 16: nal_end - nal_start + 4); h264_debug_nal(h, h->nal); } p += (nal_end - nal_start); sz -= nal_end; } // if no NALs found in buffer, discard it if (p == buf) { fprintf( stderr, "!! Did not find any NALs between offset %lld (0x%04llX), size %lld (0x%04llX), discarding \n", (long long int)off, (long long int)off, (long long int)off + sz, (long long int)off + sz); p = buf + sz; sz = 0; } memmove(buf, p, sz); off += p - buf; p = buf; } h264_free(h); free(buf); fclose(h264_dbgfile); fclose(infile); return 0; }