int write_avcc(avcc_t* avcc, h264_stream_t* h, bs_t* b) { bs_write_u8(b, 1); // configurationVersion = 1; bs_write_u8(b, avcc->AVCProfileIndication); bs_write_u8(b, avcc->profile_compatibility); bs_write_u8(b, avcc->AVCLevelIndication); bs_write_u(b, 6, 0x3F); // reserved = '111111'b; bs_write_u(b, 2, avcc->lengthSizeMinusOne); bs_write_u(b, 3, 0x07); // reserved = '111'b; bs_write_u(b, 5, avcc->numOfSequenceParameterSets); int i; for (i = 0; i < avcc->numOfSequenceParameterSets; i++) { int max_len = 1024; // FIXME uint8_t* buf = (uint8_t*)malloc(max_len); h->nal->nal_ref_idc = 3; // NAL_REF_IDC_PRIORITY_HIGHEST; h->nal->nal_unit_type = NAL_UNIT_TYPE_SPS; h->sps = avcc->sps_table[i]; int len = write_nal_unit(h, buf, max_len); if (len < 0) { free(buf); continue; } // TODO report errors int sequenceParameterSetLength = len; bs_write_u(b, 16, sequenceParameterSetLength); bs_write_bytes(b, buf, len); free(buf); } bs_write_u(b, 8, avcc->numOfPictureParameterSets); for (i = 0; i < avcc->numOfPictureParameterSets; i++) { int max_len = 1024; // FIXME uint8_t* buf = (uint8_t*)malloc(max_len); h->nal->nal_ref_idc = 3; // NAL_REF_IDC_PRIORITY_HIGHEST; h->nal->nal_unit_type = NAL_UNIT_TYPE_PPS; h->pps = avcc->pps_table[i]; int len = write_nal_unit(h, buf, max_len); if (len < 0) { free(buf); continue; } // TODO report errors int pictureParameterSetLength = len; bs_write_u(b, 16, pictureParameterSetLength); bs_write_bytes(b, buf, len); free(buf); } if (bs_overrun(b)) { return -1; } return bs_pos(b); }
int read_avcc(avcc_t* avcc, h264_stream_t* h, bs_t* b) { avcc->configurationVersion = bs_read_u8(b); avcc->AVCProfileIndication = bs_read_u8(b); avcc->profile_compatibility = bs_read_u8(b); avcc->AVCLevelIndication = bs_read_u8(b); /* int reserved = */ bs_read_u(b, 6); // '111111'b; avcc->lengthSizeMinusOne = bs_read_u(b, 2); /* int reserved = */ bs_read_u(b, 3); // '111'b; avcc->numOfSequenceParameterSets = bs_read_u(b, 5); avcc->sps_table = (sps_t**)calloc(avcc->numOfSequenceParameterSets, sizeof(sps_t*)); int i; for (i = 0; i < avcc->numOfSequenceParameterSets; i++) { int sequenceParameterSetLength = bs_read_u(b, 16); int len = sequenceParameterSetLength; uint8_t* buf = (uint8_t*)malloc(len); len = bs_read_bytes(b, buf, len); int rc = 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 = bs_read_u(b, 8); avcc->pps_table = (pps_t**)calloc(avcc->numOfSequenceParameterSets, sizeof(pps_t*)); for (i = 0; i < avcc->numOfPictureParameterSets; i++) { int pictureParameterSetLength = bs_read_u(b, 16); int len = pictureParameterSetLength; uint8_t* buf = (uint8_t*)malloc(len); len = bs_read_bytes(b, buf, len); int rc = 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 (bs_overrun(b)) { return -1; } return bs_pos(b); }
//7.3.1 NAL unit syntax int structure(nal_unit)(h264_stream_t* h, uint8_t* buf, int size) { nal_t* nal = h->nal; int nal_size = size; int rbsp_size = size; uint8_t* rbsp_buf = (uint8_t*)calloc(1, rbsp_size); if( is_reading ) { int rc = nal_to_rbsp(buf, &nal_size, rbsp_buf, &rbsp_size); if (rc < 0) { free(rbsp_buf); // handle conversion error return -1; } } if( is_writing ) { rbsp_size = size*3/4; // NOTE this may have to be slightly smaller (3/4 smaller, worst case) in order to be guaranteed to fit } bs_t* b = bs_new(rbsp_buf, rbsp_size); value( forbidden_zero_bit, f(1, 0) ); value( nal->nal_ref_idc, u(2) ); value( nal->nal_unit_type, u(5) ); switch ( nal->nal_unit_type ) { case NAL_UNIT_TYPE_CODED_SLICE_IDR: case NAL_UNIT_TYPE_CODED_SLICE_NON_IDR: case NAL_UNIT_TYPE_CODED_SLICE_AUX: structure(slice_layer_rbsp)(h, b); break; #ifdef HAVE_SEI case NAL_UNIT_TYPE_SEI: structure(sei_rbsp)(h, b); break; #endif case NAL_UNIT_TYPE_SPS: structure(seq_parameter_set_rbsp)(h, b); break; case NAL_UNIT_TYPE_PPS: structure(pic_parameter_set_rbsp)(h, b); break; case NAL_UNIT_TYPE_AUD: structure(access_unit_delimiter_rbsp)(h, b); break; case NAL_UNIT_TYPE_END_OF_SEQUENCE: structure(end_of_seq_rbsp)(h, b); break; case NAL_UNIT_TYPE_END_OF_STREAM: structure(end_of_stream_rbsp)(h, b); break; case NAL_UNIT_TYPE_FILLER: case NAL_UNIT_TYPE_SPS_EXT: case NAL_UNIT_TYPE_UNSPECIFIED: case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A: case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B: case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C: default: return -1; } if (bs_overrun(b)) { bs_free(b); free(rbsp_buf); return -1; } if( is_writing ) { // now get the actual size used rbsp_size = bs_pos(b); int rc = rbsp_to_nal(rbsp_buf, &rbsp_size, buf, &nal_size); if (rc < 0) { bs_free(b); free(rbsp_buf); return -1; } } bs_free(b); free(rbsp_buf); return nal_size; }