mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-27 19:24:06 +00:00
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:
parent
5d50872ab3
commit
c8f629495d
169
src/bitstream.c
169
src/bitstream.c
|
@ -35,6 +35,18 @@
|
|||
#include <arpa/inet.h>
|
||||
#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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
31
src/nal.c
31
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
Loading…
Reference in a new issue