More bitstream functions and better initialization

+ picture.c/.h
This commit is contained in:
Marko Viitanen 2012-06-05 14:01:47 +03:00
parent 92ebb2cd6d
commit ef5d210b18
13 changed files with 432 additions and 50 deletions

View file

@ -83,6 +83,7 @@
<ClCompile Include="..\..\src\config.c" />
<ClCompile Include="..\..\src\encmain.c" />
<ClCompile Include="..\..\src\encoder.c" />
<ClCompile Include="..\..\src\picture.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\bitstream.h" />
@ -90,6 +91,7 @@
<ClInclude Include="..\..\src\config.h" />
<ClInclude Include="..\..\src\encoder.h" />
<ClInclude Include="..\..\src\global.h" />
<ClInclude Include="..\..\src\picture.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View file

@ -30,6 +30,9 @@
<ClCompile Include="..\..\src\cabac.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\picture.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\global.h">
@ -47,5 +50,8 @@
<ClInclude Include="..\..\src\cabac.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\picture.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -31,6 +31,39 @@ void printf_bitstream(char *msg, ...)
printf("%s",buffer);
}
#endif
bitTable *exp_table;
//From wikipedia
//http://en.wikipedia.org/wiki/Binary_logarithm#Algorithm
int floorLog2(unsigned int n) {
int pos = 0;
if (n >= 1<<16) { n >>= 16; pos += 16; }
if (n >= 1<< 8) { n >>= 8; pos += 8; }
if (n >= 1<< 4) { n >>= 4; pos += 4; }
if (n >= 1<< 2) { n >>= 2; pos += 2; }
if (n >= 1<< 1) { pos += 1; }
return ((n == 0) ? (-1) : pos);
}
//Initialize the Exp Golomb code table with desired number of values
void init_exp_golomb(uint32_t len)
{
uint32_t code_num;
uint32_t M;
uint32_t info;
exp_table=(bitTable*)malloc(len*sizeof(bitTable));
for(code_num=0;code_num<len;code_num++)
{
M=(uint32_t)floorLog2(code_num+1);
info=code_num+1-(uint32_t)pow(2,M);
exp_table[code_num].len=M*2+1;
exp_table[code_num].value=(1<<M)|info;
//printf_cavlc("Len: %i %x\n", M*2+1, (1<<M)|info);
}
}
/*
* Clear bitstream
*/
@ -38,9 +71,21 @@ void bitstream_init(bitstream* stream)
{
stream->cur_byte=0;
stream->cur_bit=0;
stream->buffer_pos = 0;
memset(stream->data, 0, sizeof(uint32_t)*32);
}
/*
* Allocate buffer
*/
void bitstream_alloc(bitstream* stream, uint32_t alloc)
{
stream->buffer = (uint8_t*)malloc(alloc);
//Clear just to be sure
memset(stream->buffer,0,alloc);
stream->buffer_pos = 0;
}
/*
@ -108,25 +153,55 @@ void bitstream_put(bitstream* stream, uint32_t data, uint8_t bits)
*/
void bitstream_align(bitstream* stream)
{
if(stream->cur_byte==32)
{
//Stream flushed, zero out the values
bitstream_init(stream);
}
else
{
stream->cur_byte++;
}
if(stream->cur_bit&7 != 0)
{
bitstream_put(stream,0, 8-stream->cur_bit&7);
}
}
void bitstream_flush(bitstream* stream)
{
/*
* SAVE DATA TO OUTPUT
*/
if(stream->output)
{
if(stream->cur_byte)
{
fwrite(stream->data, stream->cur_byte*4, 1, stream->output);
}
/*
* SAVE DATA TO OUTPUT
*/
if(stream->cur_bit>>3)
{
fwrite(&stream->data[stream->cur_byte], stream->cur_bit>>3, 1, stream->output);
}
}
else
{
if(stream->cur_byte)
{
memcpy(&stream->buffer[stream->buffer_pos],&stream->data[0],stream->cur_byte*4);
stream->buffer_pos = stream->cur_byte*4;
}
if(stream->cur_bit>>3)
{
memcpy(&stream->buffer[stream->buffer_pos],&stream->data[stream->cur_byte],stream->cur_bit>>3);
stream->buffer_pos = stream->cur_bit>>3;
}
}
//Stream flushed, zero out the values
bitstream_init(stream);
}
/*
void bitstream_put_ue(bitstream* stream, uint32_t data)
{
bitstream_put(stream,exp_table[data].value,exp_table[data].len);
}
void bitstream_put_se(bitstream* stream, uint32_t data)
{
uint32_t index=(data<=0)?2*(uint32_t)(-data):2*(uint32_t)(data)-1;
bitstream_put(stream,exp_table[index].value,exp_table[index].len);
}
*/

View file

@ -15,14 +15,43 @@ typedef struct
uint8_t cur_byte;
uint8_t cur_bit;
FILE* output;
uint8_t* buffer;
uint32_t buffer_pos;
} bitstream;
typedef struct
{
uint8_t len;
uint32_t value;
}bitTable;
extern bitTable *exp_table;
void bitstream_init(bitstream* stream);
void bitstream_put(bitstream* stream, uint32_t data, uint8_t bits);
void bitstream_align(bitstream* stream);
void bitstream_alloc(bitstream* stream, uint32_t alloc);
void bitstream_init(bitstream* stream);
void bitstream_put(bitstream* stream, uint32_t data, uint8_t bits);
/*
void bitstream_put_ue(bitstream* stream, uint32_t data);
void bitstream_put_se(bitstream* stream, uint32_t data);
*/
#define bitstream_put_ue(stream, data) { bitstream_put(stream,exp_table[data].value,exp_table[data].len); }
#define bitstream_put_se(stream, data) { uint32_t index=(data<=0)?2*(uint32_t)(-data):2*(uint32_t)(data)-1; \
bitstream_put(stream,exp_table[index].value,exp_table[index].len); }
void bitstream_align(bitstream* stream);
void bitstream_flush(bitstream* stream);
void init_exp_golomb(uint32_t len);
#ifdef _DEBUG
static int WRITE_VALUE = 0;
#define WRITE_U(stream, data, bits, name) { printf("%8d %40s u(%d) : %d\n",WRITE_VALUE, name,bits,data); bitstream_put(stream,data,bits); WRITE_VALUE++;}
#define WRITE_UE(stream, data, name) { printf("%8d %40s ue(v) : %d\n",WRITE_VALUE, name,data); bitstream_put_ue(stream,data); WRITE_VALUE++;}
#define WRITE_SE(stream, data, name) { printf("%8d %40s se(v) : %d\n",WRITE_VALUE, name,data); bitstream_put_se(stream,data); WRITE_VALUE++;}
#else
#define WRITE_U(stream, data, bits, name) { bitstream_put(stream,data,bits); }
#define WRITE_UE(stream, data, name) { bitstream_put_ue(stream,data); }
#define WRITE_SE(stream, data, name) { bitstream_put_se(stream,data); }
#endif
#endif

View file

@ -122,8 +122,7 @@ void cabac_start(cabac_data* data)
data->bufferedByte = 0xff;
}
#define CTX_STATE(ctx) (ctx.ucState>>1)
#define CTX_MPS(ctx) (ctx.ucState&1)
void cabac_encodeBin(cabac_data* data, uint32_t binValue )
{
@ -193,8 +192,8 @@ void cabac_write(cabac_data* data)
{
data->numBufferedBytes = 1;
data->bufferedByte = leadByte;
}
}
}
}
}
void cabac_encodeFlush(cabac_data* data, uint8_t end )
@ -239,7 +238,7 @@ void cabac_finish(cabac_data* data)
{
bitstream_put(data->stream, 0xff, 8 );
data->numBufferedBytes--;
}
}
}
bitstream_put(data->stream, data->uiLow >> 8, 24 - data->bitsLeft );
}
@ -268,7 +267,7 @@ void cabac_encodeBinTrm(cabac_data* data, uint32_t binValue )
{
data->uiLow <<= 1;
data->uiRange <<= 1;
data->bitsLeft--;
data->bitsLeft--;
}
if(data->bitsLeft < 12)
@ -310,7 +309,7 @@ void cabac_encodeBinsEP(cabac_data* data, uint32_t binValues, int numBins )
while ( numBins > 8 )
{
numBins -= 8;
pattern = binValues >> numBins;
pattern = binValues >> numBins;
data->uiLow <<= 8;
data->uiLow += data->uiRange * pattern;
binValues -= pattern << numBins;

View file

@ -30,6 +30,8 @@ typedef struct
uint8_t ucState;
uint32_t binsCoded;
} cabac_ctx;
#define CTX_STATE(ctx) (ctx.ucState>>1)
#define CTX_MPS(ctx) (ctx.ucState&1)
void cxt_init(cabac_ctx* ctx,uint32_t qp, uint32_t initValue );
void cxt_buildNextStateTable();

View file

@ -19,12 +19,12 @@
*/
typedef struct
{
char *input; /*!< \brief Pointer to input filename */
char *output;/*!< \brief Pointer to output filename */
char *debug; /*!< \brief Pointer to debug output */
int frames; /*!< \brief Number of frames to decode */
int width; /*!< \brief frame width */
int height; /*!< \brief frame height */
char *input; /*!< \brief Pointer to input filename */
char *output; /*!< \brief Pointer to output filename */
char *debug; /*!< \brief Pointer to debug output */
uint32_t frames; /*!< \brief Number of frames to decode */
uint32_t width; /*!< \brief frame width */
uint32_t height; /*!< \brief frame height */
} config;
/* Function definitions */

View file

@ -42,6 +42,7 @@
#include "config.h"
#include "encoder.h"
#include "cabac.h"
#include "picture.h"
/*!
@ -52,7 +53,7 @@
*/
int main(int argc, char* argv[])
{
uint32_t curFrame = 0;
config *cfg = NULL; /* Global configuration */
FILE *input = NULL;
FILE *output = NULL;
@ -64,10 +65,10 @@
/* If problem with configuration, shutdown */
if(!config_init(cfg) || !config_read(cfg,argc,argv))
{
fprintf(stderr, "/////////////////////////////////////////////////\r\n");
fprintf(stderr, "// HEVC Encoder v. " VERSION_STRING "//\r\n");
fprintf(stderr, "// Tampere University of Technology 2012 //\r\n");
fprintf(stderr, "/////////////////////////////////////////////////\r\n\r\n");
fprintf(stderr, "/***********************************************/\r\n");
fprintf(stderr, " * HEVC Encoder v. " VERSION_STRING "*\r\n");
fprintf(stderr, " * Tampere University of Technology 2012 *\r\n");
fprintf(stderr, "/***********************************************/\r\n\r\n");
fprintf(stderr, "Usage:\r\n");
fprintf(stderr, "encmain -i <input> -w <width> -h <height> -o <output>\r\n");
@ -86,7 +87,7 @@
input = fopen(cfg->input, "rb");
if(input == NULL)
{
fprintf(stderr, "Couldn't open input file!\r\n");
fprintf(stderr, "Could not open input file, shutting down!\r\n");
config_destroy(cfg);
return EXIT_FAILURE;
}
@ -95,17 +96,44 @@
output = fopen(cfg->output, "wb");
if(output == NULL)
{
fprintf(stderr, "Couldn't open output file!\r\n");
fprintf(stderr, "Could not open output file, shutting down!\r\n");
config_destroy(cfg);
return EXIT_FAILURE;
}
/* Initialization */
init_exp_golomb(4096*8);
cabac_init(&cabac);
//ToDo: add bitstream
//cabac.stream =
init_encoder_control(encoder, output);
init_encoder_input(&encoder->in, input, 320, 240);
init_encoder_control(encoder, (bitstream*)malloc(sizeof(bitstream)));
/* Init bitstream */
bitstream_init(encoder->stream);
bitstream_alloc(encoder->stream, 1024*1024);
/* Config pointer to encoder struct */
encoder->cfg = cfg;
/* Set output file */
encoder->output = output;
/* Set CABAC output bitstream */
cabac.stream = encoder->stream;
/* input init */
encoder->frame = 0;
init_encoder_input(&encoder->in, input, cfg->width, cfg->height);
/* Start coding cycle */
while(!feof(input) && (!cfg->frames || curFrame < cfg->frames))
{
/* Read one frame from the input */
fread(encoder->in.cur_pic.yData, cfg->width*cfg->height,1,input);
fread(encoder->in.cur_pic.uData, cfg->width*cfg->height/4,1,input);
fread(encoder->in.cur_pic.vData, cfg->width*cfg->height/4,1,input);
encode_one_frame(encoder);
encoder->frame++;
}
/* Coding finished */
fclose(input);
fclose(output);

View file

@ -0,0 +1,48 @@
/**
* HEVC Encoder
* - Marko Viitanen ( fador at iki.fi ), Tampere University of Technology, Department of Computer Systems.
*/
/*! \file encoder.c
\brief Encoding related functions
\author Marko Viitanen
\date 2012-06
Encoder main level
*/
/* Suppress some windows warnings */
#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "global.h"
#include "config.h"
#include "encoder.h"
#include "cabac.h"
#include "picture.h"
void init_encoder_control(encoder_control* control,bitstream* output) {control->stream = output;};
void init_encoder_input(encoder_input* input,FILE* inputfile, uint32_t width, uint32_t height)
{
input->file = inputfile;
input->width = width;
input->height = height;
input->cur_pic.width = width;
input->cur_pic.height = height;
input->cur_pic.referenced = 0;
/* Allocate buffers */
input->cur_pic.yData = (uint8_t *)malloc(width*height);
input->cur_pic.uData = (uint8_t *)malloc((width*height)>>2);
input->cur_pic.vData = (uint8_t *)malloc((width*height)>>2);
};
void encode_one_frame(encoder_control* encoder)
{
}

View file

@ -13,34 +13,44 @@
#ifndef _ENCODER_H
#define _ENCODER_H
#include "bitstream.h"
#include "picture.h"
typedef struct encoder_control;
//ToDo: add ME data
typedef struct
{
//void (*IME)(encoder_control* encoder);
void (*IME)();
void (*FME)();
int range;
} encoder_me;
/* Input info struct */
typedef struct
{
FILE* file;
uint32_t width;
uint32_t height;
uint32_t height_in_LCU;
uint32_t width_in_LCU;
uint32_t width_in_LCU;
picture cur_pic;
} encoder_input;
typedef struct
{
uint32_t frame;
config *cfg;
encoder_input in;
encoder_me me;
FILE* output;
bitstream* stream;
FILE *output;
picture_list *ref;
} encoder_control;
init_encoder_control(encoder_control* control,FILE* output) {control->output = output;};
init_encoder_input(encoder_input* input,FILE* inputfile, uint32_t width, uint32_t height) {input->file = inputfile; input->width = width; input->height = height;};
void init_encoder_control(encoder_control* control,bitstream* output);
void init_encoder_input(encoder_input* input,FILE* inputfile, uint32_t width, uint32_t height);
void encode_one_frame(encoder_control* encoder);
#endif

View file

@ -23,6 +23,7 @@
#define MAX(a,b) (((a)<(b))?(b):(a))
#define MIN(a,b) (((a)>(b))?(b):(a))
#define LCU 64 /*!< Largest Coding Unit */
#define VERSION_STRING "0.1 "
#define VERSION 0.1

125
src/picture.c Normal file
View file

@ -0,0 +1,125 @@
/**
* Part of HEVC Encoder
* By Marko Viitanen ( fador at iki.fi ), Tampere University of Technology, Department of Computer Systems.
*/
/*! \file picture.c
\brief Functions to handle pictures
\author Marko Viitanen
\date 2012-06
This file contains all the needed functions to handle pictures
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "global.h"
#include "picture.h"
/** \defgroup picture_group Picture handler group
* This group contains all picture related stuff
* @{
*/
/*!
\brief Allocate memory for picture_list
\param size initial array size
\return picture_list pointer, NULL on failure
*/
picture_list *picture_list_init(int size)
{
picture_list *list = (picture_list *)malloc(sizeof(picture_list));
list->size = size;
if(size > 0)
{
list->pics = (picture**)malloc(sizeof(picture*)*size);
}
list->used_size = 0;
return list;
}
/*!
\brief Resize picture_list array
\param list picture_list pointer
\param size new array size
\return 1 on success, 0 on failure
*/
int picture_list_resize(picture_list *list, int size)
{
unsigned int i;
picture** old_pics = NULL;
//No need to do anything when resizing to same size
if(size == list->size)
{
return 1;
}
//Save the old list
if(list->used_size > 0)
{
old_pics = list->pics;
}
//allocate space for the new list
list->pics = (picture**)malloc(sizeof(picture*)*size);
//Copy everthing from the old list to the new if needed.
if(old_pics != NULL)
{
for(i = 0; i < list->used_size; i++)
{
list->pics[i] = old_pics[i];
}
free(old_pics);
}
return 1;
}
/*!
\brief Free memory allocated to the picture_list
\param list picture_list pointer
\return 1 on success, 0 on failure
*/
int picture_list_destroy(picture_list *list)
{
unsigned int i;
if(list->used_size > 0)
{
for(i = 0; i < list->used_size; i++)
{
picture_destroy(list->pics[i]);
}
}
if(list->size > 0)
{
free(list->pics);
}
free(list);
return 1;
}
/*!
\brief Free memory allocated to picture
\param pic picture pointer
\return 1 on success, 0 on failure
*/
int picture_destroy(picture *pic)
{
free(pic->uData);
free(pic->vData);
free(pic->yData);
return 1;
}
/** @} */ // end of group1

57
src/picture.h Normal file
View file

@ -0,0 +1,57 @@
/**
* Part of HEVC Encoder
* By Marko Viitanen ( fador at iki.fi ), Tampere University of Technology, Department of Computer Systems.
*/
/*! \file picture.h
\brief Picture header
\author Marko Viitanen
\date 2012-06
Contains all picture related functions and structs
*/
#ifndef _PICTURE_H_
#define _PICTURE_H_
/** \defgroup picture_group Picture handler group
* This group contains all picture related stuff
* @{
*/
/*!
\brief Struct which contains all picture data
*/
typedef struct
{
uint8_t* yData; /*!< \brief Pointer to Y-data */
uint8_t* uData; /*!< \brief Pointer to U-data */
uint8_t* vData; /*!< \brief Pointer to V-data */
int width; /*!< \brief Picture width */
int height; /*!< \brief Picture height */
uint8_t referenced; /*!< \brief Is this picture referenced */
} picture;
/*!
\brief Struct which contains array of picture structs
*/
typedef struct
{
picture** pics; /*!< \brief Pointer to array of picture pointers */
unsigned int size; /*!< \brief Array size */
unsigned int used_size;
} picture_list;
picture_list *picture_list_init(int size);
int picture_list_resize(picture_list *list, int size);
int picture_list_destroy(picture_list *list);
int picture_destroy(picture *pic);
/** @} */ // end of group1
#endif