Remove unnecessary buffer from bitstream.

- Writing encoded data to file is done in bitstream_put one byte at a time and nal_write only writes the packet headers
This commit is contained in:
Panu Sjövall 2014-03-24 15:31:15 +02:00 committed by Marko Viitanen
parent 5d50872ab3
commit c8f629495d
6 changed files with 65 additions and 217 deletions

View file

@ -35,6 +35,18 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #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 //#define VERBOSE
@ -93,7 +105,7 @@ int init_exp_golomb(uint32_t len)
/** /**
* \brief Create and initialize a new bitstream * \brief Create and initialize a new bitstream
*/ */
bitstream *create_bitstream(int32_t width) bitstream *create_bitstream()
{ {
bitstream *stream = malloc(sizeof(bitstream)); bitstream *stream = malloc(sizeof(bitstream));
if (!stream) { if (!stream) {
@ -101,74 +113,13 @@ bitstream *create_bitstream(int32_t width)
return stream; return stream;
} }
// Initialize the bitstream
bitstream_reinit(stream);
// Initialize buffer-related values // Initialize buffer-related values
stream->output = NULL; stream->data = 0;
stream->buffer = NULL; stream->cur_bit = 0;
stream->buffer_pos = 0; stream->zerocount = 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);
// Return the created bitstream // Return the created bitstream
return stream; 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) void bitstream_put(bitstream *stream, uint32_t data, uint8_t bits)
{ {
uint8_t bitsleft = 32 - stream->cur_bit; const uint8_t emulation_prevention_three_byte = 0x03;
#ifdef VERBOSE while(bits--) {
uint8_t i=0; stream->data <<= 1;
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
//There's space for all the bits if (data & bit_set_mask[bits]) {
if (bits <= bitsleft) { stream->data |= 1;
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);
} }
} stream->cur_bit++;
//Write the last of the bits (if buffer was full and flushed before) // write byte to output
if (bits != 0) { if (stream->cur_bit==8) {
stream->data[stream->cur_byte] |= (data<<(bitsleft-bits)); if((stream->zerocount == 2) && (stream->data < 4)) {
stream->cur_bit += bits; 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) { if ((stream->cur_bit & 7) != 0) {
bitstream_put(stream, 0, 8 - (stream->cur_bit & 7)); 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);
}

View file

@ -29,13 +29,10 @@
typedef struct typedef struct
{ {
uint32_t data[32]; uint8_t data;
uint8_t cur_byte; uint8_t cur_bit;
uint8_t cur_bit; uint8_t zerocount;
FILE* output; FILE* output;
uint8_t* buffer;
uint32_t buffer_pos;
uint32_t bufferlen;
} bitstream; } bitstream;
typedef struct typedef struct
@ -48,11 +45,7 @@ extern bit_table *g_exp_table;
int floor_log2(unsigned int n); int floor_log2(unsigned int n);
bitstream *create_bitstream(int32_t width); bitstream *create_bitstream();
void bitstream_alloc(bitstream* stream, uint32_t alloc);
void bitstream_free(bitstream *stream);
void bitstream_clear_buffer(bitstream* stream);
void bitstream_reinit(bitstream *stream);
void bitstream_put(bitstream* stream, uint32_t data, uint8_t bits); void bitstream_put(bitstream* stream, uint32_t data, uint8_t bits);
/* Use macros to force inlining */ /* 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(bitstream* stream);
void bitstream_align_zero(bitstream* stream); void bitstream_align_zero(bitstream* stream);
void bitstream_flush(bitstream* stream);
int init_exp_golomb(uint32_t len); int init_exp_golomb(uint32_t len);

View file

@ -208,8 +208,9 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
// Set output file // Set output file
encoder->output = output;
encoder->output = output;
encoder->stream->output = output;
// input init (TODO: read from commandline / config) // input init (TODO: read from commandline / config)
encoder->bitdepth = 8; encoder->bitdepth = 8;
encoder->frame = 0; encoder->frame = 0;
@ -386,7 +387,6 @@ int main(int argc, char *argv[])
picture_list_destroy(encoder->ref); picture_list_destroy(encoder->ref);
picture_destroy(encoder->in.cur_pic); picture_destroy(encoder->in.cur_pic);
FREE_POINTER(encoder->in.cur_pic); FREE_POINTER(encoder->in.cur_pic);
bitstream_free(encoder->stream);
FREE_POINTER(encoder->stream); FREE_POINTER(encoder->stream);
free(encoder); free(encoder);
free_tables(); free_tables();

View file

@ -279,7 +279,7 @@ encoder_control *init_encoder_control(config *cfg)
enc_c->sao_enable = 1; enc_c->sao_enable = 1;
// Allocate the bitstream struct // Allocate the bitstream struct
stream = create_bitstream(enc_c->cfg->width); stream = create_bitstream();
if (!stream) { if (!stream) {
fprintf(stderr, "Failed to allocate the bitstream object!\n"); fprintf(stderr, "Failed to allocate the bitstream object!\n");
goto init_failure; goto init_failure;
@ -377,11 +377,8 @@ void init_encoder_input(encoder_input *input, FILE *inputfile,
static void write_aud(encoder_control* encoder) static void write_aud(encoder_control* encoder)
{ {
encode_access_unit_delimiter(encoder); encode_access_unit_delimiter(encoder);
nal_write(encoder->output, 0, AUD_NUT, 0, 1);
bitstream_align(encoder->stream); 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) void encode_one_frame(encoder_control* encoder)
@ -424,37 +421,25 @@ void encode_one_frame(encoder_control* encoder)
write_aud(encoder); write_aud(encoder);
// Video Parameter Set (VPS) // Video Parameter Set (VPS)
nal_write(encoder->output, 0, NAL_VPS_NUT, 0, 1);
encode_vid_parameter_set(encoder); encode_vid_parameter_set(encoder);
bitstream_align(encoder->stream); 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) // Sequence Parameter Set (SPS)
nal_write(encoder->output, 0, NAL_SPS_NUT, 0, 1);
encode_seq_parameter_set(encoder); encode_seq_parameter_set(encoder);
bitstream_align(encoder->stream); 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) // Picture Parameter Set (PPS)
nal_write(encoder->output, 0, NAL_PPS_NUT, 0, 1);
encode_pic_parameter_set(encoder); encode_pic_parameter_set(encoder);
bitstream_align(encoder->stream); 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) { if (encoder->frame == 0) {
// Prefix SEI // Prefix SEI
nal_write(encoder->output, 0, PREFIX_SEI_NUT, 0, 0);
encode_prefix_sei_version(encoder); encode_prefix_sei_version(encoder);
bitstream_align(encoder->stream); 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 { } else {
// When intra period == 1, all pictures are intra // When intra period == 1, all pictures are intra
@ -466,6 +451,15 @@ void encode_one_frame(encoder_control* encoder)
write_aud(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); cabac_start(&cabac);
init_contexts(encoder, encoder->in.cur_pic->slicetype); init_contexts(encoder, encoder->in.cur_pic->slicetype);
scalinglist_process(); scalinglist_process();
@ -561,19 +555,6 @@ void encode_one_frame(encoder_control* encoder)
cabac_flush(&cabac); cabac_flush(&cabac);
bitstream_align(encoder->stream); 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) { if (encoder->sao_enable) {
sao_reconstruct_frame(encoder); sao_reconstruct_frame(encoder);
@ -679,6 +660,8 @@ static void add_checksum(encoder_control* encoder)
uint32_t checksum_val; uint32_t checksum_val;
unsigned int i; unsigned int i;
nal_write(encoder->output, 0, NAL_SUFFIT_SEI_NUT, 0, 0);
picture_checksum(encoder->in.cur_pic, checksum); picture_checksum(encoder->in.cur_pic, checksum);
WRITE_U(encoder->stream, 132, 8, "sei_type"); WRITE_U(encoder->stream, 132, 8, "sei_type");
@ -694,10 +677,6 @@ static void add_checksum(encoder_control* encoder)
} }
bitstream_align(encoder->stream); 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) void encode_access_unit_delimiter(encoder_control* encoder)

View file

@ -35,16 +35,12 @@
/** /**
* \brief Write a Network Abstraction Layer (NAL) packet to the output. * \brief Write a Network Abstraction Layer (NAL) packet to the output.
*/ */
void nal_write(FILE *output, uint8_t *buffer, uint32_t buffer_len, void nal_write(FILE *output,uint8_t nal_ref, uint8_t nal_type,
uint8_t nal_ref, uint8_t nal_type, uint8_t temporal_id, uint8_t temporal_id,int long_start_code)
int long_start_code)
{ {
uint8_t byte; uint8_t byte;
uint32_t i;
uint8_t zerocount = 0;
// Some useful constants // Some useful constants
const uint8_t emulation_prevention_three_byte = 0x03;
const uint8_t start_code_prefix_one_3bytes = 0x01; const uint8_t start_code_prefix_one_3bytes = 0x01;
const uint8_t zero = 0x00; 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) // 5bits of nuh_layer_id + nuh_temporal_id_plus1(3)
byte = (temporal_id + 1) & 7; byte = (temporal_id + 1) & 7;
fwrite(&byte, 1, 1, output); 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);
}
} }

View file

@ -92,9 +92,8 @@ enum {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// FUNCTIONS // FUNCTIONS
void nal_write(FILE *output, uint8_t *buffer, uint32_t buffer_len, void nal_write(FILE *output,uint8_t nal_ref, uint8_t nal_type,
uint8_t nal_ref, uint8_t nal_type, uint8_t temporal_id, uint8_t temporal_id,int long_start_code);
int long_start_code);
void picture_checksum(const picture *pic, void picture_checksum(const picture *pic,
unsigned char checksum_out[][SEI_HASH_MAX_LENGTH]); unsigned char checksum_out[][SEI_HASH_MAX_LENGTH]);