diff --git a/src/bitstream.c b/src/bitstream.c index 382375d2..2b1c3b85 100644 --- a/src/bitstream.c +++ b/src/bitstream.c @@ -35,6 +35,18 @@ #include #endif +const uint32_t bit_set_mask[] = +{ +0x00000001,0x00000002,0x00000004,0x00000008, +0x00000010,0x00000020,0x00000040,0x00000080, +0x00000100,0x00000200,0x00000400,0x00000800, +0x00001000,0x00002000,0x00004000,0x00008000, +0x00010000,0x00020000,0x00040000,0x00080000, +0x00100000,0x00200000,0x00400000,0x00800000, +0x01000000,0x02000000,0x04000000,0x08000000, +0x10000000,0x20000000,0x40000000,0x80000000 +}; + //#define VERBOSE @@ -93,7 +105,7 @@ int init_exp_golomb(uint32_t len) /** * \brief Create and initialize a new bitstream */ -bitstream *create_bitstream(int32_t width) +bitstream *create_bitstream() { bitstream *stream = malloc(sizeof(bitstream)); if (!stream) { @@ -101,74 +113,13 @@ bitstream *create_bitstream(int32_t width) return stream; } - // Initialize the bitstream - bitstream_reinit(stream); - // Initialize buffer-related values - stream->output = NULL; - stream->buffer = NULL; - stream->buffer_pos = 0; - stream->bufferlen = 0; - - // Alloc 2kB*width for bitstream buffer (for one coded frame) - bitstream_alloc(stream, 1024*2*width); - if (!stream->buffer) { - fprintf(stderr, "Failed to allocate the bitstream buffer!\n"); - goto creation_failure; - } - - //Clear buffer just to be sure - bitstream_clear_buffer(stream); + stream->data = 0; + stream->cur_bit = 0; + stream->zerocount = 0; // Return the created bitstream return stream; - -creation_failure: - // In case of failure, free whatever was allocated - free(stream->buffer); - free(stream); - - return NULL; -} - -/** - * \brief Reinitialize bitstream - */ -void bitstream_reinit(bitstream *stream) -{ - stream->cur_byte = 0; - stream->cur_bit = 0; - memset(stream->data, 0, sizeof(uint32_t)*32); -} - -/** - * \brief Allocate buffer - * \param stream pointer bitstream to put the data - * \param alloc size to allocate - */ -void bitstream_alloc(bitstream *stream, uint32_t alloc) -{ - stream->buffer = (uint8_t*)malloc(alloc); - if (stream->buffer) - stream->bufferlen = alloc; -} - -/** - * \brief Free bitstream buffer - */ -void bitstream_free(bitstream *stream) -{ - free(stream->buffer); - stream->bufferlen = 0; -} - -/** - * \brief clear output buffer - */ -void bitstream_clear_buffer(bitstream *stream) -{ - memset(stream->buffer, 0, stream->bufferlen); - stream->buffer_pos = 0; } /** @@ -179,43 +130,29 @@ void bitstream_clear_buffer(bitstream *stream) */ void bitstream_put(bitstream *stream, uint32_t data, uint8_t bits) { - uint8_t bitsleft = 32 - stream->cur_bit; - #ifdef VERBOSE - uint8_t i=0; - printf_bitstream("put: "); - for (i = 0; i < bits; i++) { - printf("%i",(data&(1<<(bits-i-1)))?1:0); - } - printf_bitstream("\n"); - //printf_bitstream(" count: %i\n",bits); - #endif + const uint8_t emulation_prevention_three_byte = 0x03; + while(bits--) { + stream->data <<= 1; - //There's space for all the bits - if (bits <= bitsleft) { - stream->data[stream->cur_byte] |= (data<<((bitsleft-bits))); - stream->cur_bit += bits; - bits = 0; - } else { //No space for everything, store the bits we can and continue later - stream->data[stream->cur_byte] |= (data>>(bits-bitsleft)); - stream->cur_bit = 32; - bits -= bitsleft; - } - - //Check if the buffer is full, and flush to output if it is - if (stream->cur_bit == 32) { - bitsleft = 32; - stream->cur_byte++; - stream->cur_bit = 0; - if (stream->cur_byte == 32) { - //Flush data out - bitstream_flush(stream); + if (data & bit_set_mask[bits]) { + stream->data |= 1; } - } + stream->cur_bit++; - //Write the last of the bits (if buffer was full and flushed before) - if (bits != 0) { - stream->data[stream->cur_byte] |= (data<<(bitsleft-bits)); - stream->cur_bit += bits; + // write byte to output + if (stream->cur_bit==8) { + if((stream->zerocount == 2) && (stream->data < 4)) { + fwrite(&emulation_prevention_three_byte, 1, 1, stream->output); + stream->zerocount = 0; + } + if(stream->data == 0) { + stream->zerocount++; + } else { + stream->zerocount = 0; + } + fwrite(&stream->data, 1, 1, stream->output); + stream->cur_bit = 0; + } } } @@ -238,36 +175,4 @@ void bitstream_align_zero(bitstream *stream) if ((stream->cur_bit & 7) != 0) { bitstream_put(stream, 0, 8 - (stream->cur_bit & 7)); } -} - -/** - * \brief Flush bitstream to output - */ -void bitstream_flush(bitstream *stream) -{ - int i; - uint32_t correct_endian; - //If output open, write to output - if (stream->output) { - if (stream->cur_byte) fwrite(&stream->data[0], stream->cur_byte * 4, 1, stream->output); - if (stream->cur_bit>>3) fwrite(&stream->data[stream->cur_byte], stream->cur_bit>>3, 1, stream->output); - } else { //No file open, write to buffer - if (stream->cur_byte) { - //Handle endianness issue - for (i = 0; i < stream->cur_byte; i++) { - //"network" is big-endian - correct_endian = htonl(stream->data[i]); - memcpy((uint8_t*)&stream->buffer[stream->buffer_pos], &correct_endian, 4); - stream->buffer_pos += 4; - } - } - - if (stream->cur_bit>>3) { - correct_endian = htonl(stream->data[stream->cur_byte]); - memcpy((uint8_t*)&stream->buffer[stream->buffer_pos], &correct_endian, stream->cur_bit>>3); - stream->buffer_pos += stream->cur_bit>>3; - } - } - //Stream flushed, zero out the values - bitstream_reinit(stream); -} +} \ No newline at end of file diff --git a/src/bitstream.h b/src/bitstream.h index 7d4ba5aa..6e5413eb 100644 --- a/src/bitstream.h +++ b/src/bitstream.h @@ -29,13 +29,10 @@ typedef struct { - uint32_t data[32]; - uint8_t cur_byte; - uint8_t cur_bit; - FILE* output; - uint8_t* buffer; - uint32_t buffer_pos; - uint32_t bufferlen; + uint8_t data; + uint8_t cur_bit; + uint8_t zerocount; + FILE* output; } bitstream; typedef struct @@ -48,11 +45,7 @@ extern bit_table *g_exp_table; int floor_log2(unsigned int n); -bitstream *create_bitstream(int32_t width); -void bitstream_alloc(bitstream* stream, uint32_t alloc); -void bitstream_free(bitstream *stream); -void bitstream_clear_buffer(bitstream* stream); -void bitstream_reinit(bitstream *stream); +bitstream *create_bitstream(); void bitstream_put(bitstream* stream, uint32_t data, uint8_t bits); /* Use macros to force inlining */ @@ -62,7 +55,6 @@ void bitstream_put(bitstream* stream, uint32_t data, uint8_t bits); void bitstream_align(bitstream* stream); void bitstream_align_zero(bitstream* stream); -void bitstream_flush(bitstream* stream); int init_exp_golomb(uint32_t len); diff --git a/src/encmain.c b/src/encmain.c index 236d5b87..f33428a6 100644 --- a/src/encmain.c +++ b/src/encmain.c @@ -208,8 +208,9 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; // Set output file - encoder->output = output; + encoder->output = output; + encoder->stream->output = output; // input init (TODO: read from commandline / config) encoder->bitdepth = 8; encoder->frame = 0; @@ -386,7 +387,6 @@ int main(int argc, char *argv[]) picture_list_destroy(encoder->ref); picture_destroy(encoder->in.cur_pic); FREE_POINTER(encoder->in.cur_pic); - bitstream_free(encoder->stream); FREE_POINTER(encoder->stream); free(encoder); free_tables(); diff --git a/src/encoder.c b/src/encoder.c index 003387a9..99d7faac 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -279,7 +279,7 @@ encoder_control *init_encoder_control(config *cfg) enc_c->sao_enable = 1; // Allocate the bitstream struct - stream = create_bitstream(enc_c->cfg->width); + stream = create_bitstream(); if (!stream) { fprintf(stderr, "Failed to allocate the bitstream object!\n"); goto init_failure; @@ -377,11 +377,8 @@ void init_encoder_input(encoder_input *input, FILE *inputfile, static void write_aud(encoder_control* encoder) { encode_access_unit_delimiter(encoder); + nal_write(encoder->output, 0, AUD_NUT, 0, 1); bitstream_align(encoder->stream); - bitstream_flush(encoder->stream); - nal_write(encoder->output, encoder->stream->buffer, - encoder->stream->buffer_pos, 0, AUD_NUT, 0, 1); - bitstream_clear_buffer(encoder->stream); } void encode_one_frame(encoder_control* encoder) @@ -424,37 +421,25 @@ void encode_one_frame(encoder_control* encoder) write_aud(encoder); // Video Parameter Set (VPS) + nal_write(encoder->output, 0, NAL_VPS_NUT, 0, 1); encode_vid_parameter_set(encoder); bitstream_align(encoder->stream); - bitstream_flush(encoder->stream); - nal_write(encoder->output, encoder->stream->buffer, - encoder->stream->buffer_pos, 0, NAL_VPS_NUT, 0, 1); - bitstream_clear_buffer(encoder->stream); // Sequence Parameter Set (SPS) + nal_write(encoder->output, 0, NAL_SPS_NUT, 0, 1); encode_seq_parameter_set(encoder); bitstream_align(encoder->stream); - bitstream_flush(encoder->stream); - nal_write(encoder->output, encoder->stream->buffer, - encoder->stream->buffer_pos, 0, NAL_SPS_NUT, 0, 1); - bitstream_clear_buffer(encoder->stream); // Picture Parameter Set (PPS) + nal_write(encoder->output, 0, NAL_PPS_NUT, 0, 1); encode_pic_parameter_set(encoder); bitstream_align(encoder->stream); - bitstream_flush(encoder->stream); - nal_write(encoder->output, encoder->stream->buffer, - encoder->stream->buffer_pos, 0, NAL_PPS_NUT, 0, 1); - bitstream_clear_buffer(encoder->stream); if (encoder->frame == 0) { // Prefix SEI + nal_write(encoder->output, 0, PREFIX_SEI_NUT, 0, 0); encode_prefix_sei_version(encoder); bitstream_align(encoder->stream); - bitstream_flush(encoder->stream); - nal_write(encoder->output, encoder->stream->buffer, - encoder->stream->buffer_pos, 0, PREFIX_SEI_NUT, 0, 0); - bitstream_clear_buffer(encoder->stream); } } else { // When intra period == 1, all pictures are intra @@ -466,6 +451,15 @@ void encode_one_frame(encoder_control* encoder) write_aud(encoder); } + { + // Not quite sure if this is correct, but it seems to have worked so far + // so I tried to not change it's behavior. + int long_start_code = is_radl_frame || encoder->aud_enable ? 0 : 1; + + nal_write(encoder->output, 0, + is_radl_frame ? NAL_IDR_W_RADL : NAL_TRAIL_R, 0, long_start_code); + } + cabac_start(&cabac); init_contexts(encoder, encoder->in.cur_pic->slicetype); scalinglist_process(); @@ -561,19 +555,6 @@ void encode_one_frame(encoder_control* encoder) cabac_flush(&cabac); bitstream_align(encoder->stream); - bitstream_flush(encoder->stream); - - { - // Not quite sure if this is correct, but it seems to have worked so far - // so I tried to not change it's behavior. - int long_start_code = is_radl_frame || encoder->aud_enable ? 0 : 1; - - nal_write(encoder->output, encoder->stream->buffer, - encoder->stream->buffer_pos, 0, - is_radl_frame ? NAL_IDR_W_RADL : NAL_TRAIL_R, 0, long_start_code); - } - - bitstream_clear_buffer(encoder->stream); if (encoder->sao_enable) { sao_reconstruct_frame(encoder); @@ -679,6 +660,8 @@ static void add_checksum(encoder_control* encoder) uint32_t checksum_val; unsigned int i; + nal_write(encoder->output, 0, NAL_SUFFIT_SEI_NUT, 0, 0); + picture_checksum(encoder->in.cur_pic, checksum); WRITE_U(encoder->stream, 132, 8, "sei_type"); @@ -694,10 +677,6 @@ static void add_checksum(encoder_control* encoder) } bitstream_align(encoder->stream); - bitstream_flush(encoder->stream); - nal_write(encoder->output, encoder->stream->buffer, - encoder->stream->buffer_pos, 0, NAL_SUFFIT_SEI_NUT, 0, 0); - bitstream_clear_buffer(encoder->stream); } void encode_access_unit_delimiter(encoder_control* encoder) diff --git a/src/nal.c b/src/nal.c index fb0fe02f..24c57d56 100644 --- a/src/nal.c +++ b/src/nal.c @@ -35,16 +35,12 @@ /** * \brief Write a Network Abstraction Layer (NAL) packet to the output. */ -void nal_write(FILE *output, uint8_t *buffer, uint32_t buffer_len, - uint8_t nal_ref, uint8_t nal_type, uint8_t temporal_id, - int long_start_code) +void nal_write(FILE *output,uint8_t nal_ref, uint8_t nal_type, + uint8_t temporal_id,int long_start_code) { uint8_t byte; - uint32_t i; - uint8_t zerocount = 0; // Some useful constants - const uint8_t emulation_prevention_three_byte = 0x03; const uint8_t start_code_prefix_one_3bytes = 0x01; const uint8_t zero = 0x00; @@ -70,29 +66,6 @@ void nal_write(FILE *output, uint8_t *buffer, uint32_t buffer_len, // 5bits of nuh_layer_id + nuh_temporal_id_plus1(3) byte = (temporal_id + 1) & 7; fwrite(&byte, 1, 1, output); - - // Write out bytes and add emulation_prevention_three_byte when needed - for (i = 0; i < buffer_len; ++i) { - // Prevent 0x0000 + 00/01/02 byte sequences from occurring by prefixing - // the last byte with 0x03. Do the same for 0x03. - if (zerocount == 2 && buffer[i] < 4) { - fwrite(&emulation_prevention_three_byte, 1, 1, output); - zerocount = 0; - } - if(buffer[i] == 0) { - zerocount++; - } else { - zerocount = 0; - } - - // Write the actual data - fwrite(&buffer[i], 1, 1, output); - } - - // If last byte was 0, add emulation_prevention_three_byte - if (buffer[buffer_len - 1] == 0) { - fwrite(&emulation_prevention_three_byte, 1, 1, output); - } } diff --git a/src/nal.h b/src/nal.h index 2f5fc140..dc5d4648 100644 --- a/src/nal.h +++ b/src/nal.h @@ -92,9 +92,8 @@ enum { ////////////////////////////////////////////////////////////////////////// // FUNCTIONS -void nal_write(FILE *output, uint8_t *buffer, uint32_t buffer_len, - uint8_t nal_ref, uint8_t nal_type, uint8_t temporal_id, - int long_start_code); +void nal_write(FILE *output,uint8_t nal_ref, uint8_t nal_type, + uint8_t temporal_id,int long_start_code); void picture_checksum(const picture *pic, unsigned char checksum_out[][SEI_HASH_MAX_LENGTH]);