diff --git a/build/VS2010/HEVC_encoder.vcxproj b/build/VS2010/HEVC_encoder.vcxproj index cbbd3e8f..6622f69f 100644 --- a/build/VS2010/HEVC_encoder.vcxproj +++ b/build/VS2010/HEVC_encoder.vcxproj @@ -83,6 +83,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/build/VS2010/HEVC_encoder.vcxproj.filters b/build/VS2010/HEVC_encoder.vcxproj.filters index fc706a68..dce2d423 100644 --- a/build/VS2010/HEVC_encoder.vcxproj.filters +++ b/build/VS2010/HEVC_encoder.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + @@ -47,5 +50,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/src/bitstream.c b/src/bitstream.c index f67041f5..32c697bc 100644 --- a/src/bitstream.c +++ b/src/bitstream.c @@ -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_numcur_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); } - \ No newline at end of file + +/* +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); +} +*/ \ No newline at end of file diff --git a/src/bitstream.h b/src/bitstream.h index 53377137..f72101cb 100644 --- a/src/bitstream.h +++ b/src/bitstream.h @@ -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 \ No newline at end of file diff --git a/src/cabac.c b/src/cabac.c index d1548626..239348e2 100644 --- a/src/cabac.c +++ b/src/cabac.c @@ -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; diff --git a/src/cabac.h b/src/cabac.h index 34717ef8..691eda6f 100644 --- a/src/cabac.h +++ b/src/cabac.h @@ -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(); diff --git a/src/config.h b/src/config.h index 3141b665..1fe78644 100644 --- a/src/config.h +++ b/src/config.h @@ -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 */ diff --git a/src/encmain.c b/src/encmain.c index e165b72b..934e40ab 100644 --- a/src/encmain.c +++ b/src/encmain.c @@ -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 -w -h -o \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); diff --git a/src/encoder.c b/src/encoder.c index e69de29b..dc14506b 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -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 +#include +#include +#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) +{ + + +} \ No newline at end of file diff --git a/src/encoder.h b/src/encoder.h index e7ff94d4..af6d77b1 100644 --- a/src/encoder.h +++ b/src/encoder.h @@ -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 \ No newline at end of file diff --git a/src/global.h b/src/global.h index b4ac14b0..356d2312 100644 --- a/src/global.h +++ b/src/global.h @@ -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 diff --git a/src/picture.c b/src/picture.c new file mode 100644 index 00000000..9e0cf7b1 --- /dev/null +++ b/src/picture.c @@ -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 +#include +#include +#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 \ No newline at end of file diff --git a/src/picture.h b/src/picture.h new file mode 100644 index 00000000..53a4a6b1 --- /dev/null +++ b/src/picture.h @@ -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 \ No newline at end of file