/*! *********************************************************************** * \mainpage * This is the H.264/AVC decoder reference software. For detailed documentation * see the comments in each file. * * The JM software web site is located at: * http://iphome.hhi.de/suehring/tml * * For bug reporting and known issues see: * https://ipbt.hhi.de * * \author * The main contributors are listed in contributors.h * * \version * JM 16.1 (FRExt) * * \note * tags are used for document system "doxygen" * available at http://www.doxygen.org */ /*! * \file * ldecod.c * \brief * H.264/AVC reference decoder project main() * \author * Main contributors (see contributors.h for copyright, address and affiliation details) * - Inge Lille-Langøy * - Rickard Sjoberg * - Stephan Wenger * - Jani Lainema * - Sebastian Purreiter * - Byeong-Moon Jeon * - Gabi Blaettermann * - Ye-Kui Wang * - Valeri George * - Karsten Suehring * *********************************************************************** */ #include "contributors.h" #include #include "global.h" #include "image.h" #include "memalloc.h" #include "mc_prediction.h" #include "mbuffer.h" #include "leaky_bucket.h" #include "fmo.h" #include "output.h" #include "cabac.h" #include "parset.h" #include "sei.h" #include "erc_api.h" #include "quant.h" #include "block.h" #include "nalu.h" #include "meminput.h" #define LOGFILE "log.dec" #define DATADECFILE "dataDec.txt" #define TRACEFILE "trace_dec.txt" // Decoder definition. This should be the only global variable in the entire // software. Global variables should be avoided. char errortext[ET_SIZE]; //!< buffer for error message for exit with error() #ifdef TRACE FILE *p_trace=0; int bitcounter=0; #endif // Prototypes of static functions void init (VideoParameters *p_Vid); void malloc_slice(InputParameters *p_Inp, VideoParameters *p_Vid); void free_slice (Slice *currSlice); void init_frext(VideoParameters *p_Vid); /*! ************************************************************************ * \brief * Error handling procedure. Print error message to stderr and exit * with supplied code. * \param text * Error message * \param code * Exit code ************************************************************************ */ void error(char *text, int code) { RaiseException(code, 0, 1, (ULONG_PTR *)text); //fprintf(stderr, "%s\n", text); //flush_dpb(p_Dec->p_Vid); //exit(code); } /*static */void Configure(VideoParameters *p_Vid, InputParameters *p_Inp) { p_Vid->p_Inp = p_Inp; p_Inp->intra_profile_deblocking = 0; #ifdef _LEAKYBUCKET_ p_Inp->R_decoder=500000; //! Decoder rate p_Inp->B_decoder=104000; //! Decoder buffer size p_Inp->F_decoder=73000; //! Decoder initial delay strcpy(p_Inp->LeakyBucketParamFile,"leakybucketparam.cfg"); // file where Leaky Bucket parameters (computed by encoder) are stored #endif } /*! *********************************************************************** * \brief * Allocate the Image structure * \par Output: * Image Parameters VideoParameters *p_Vid *********************************************************************** */ static void alloc_img( VideoParameters **p_Vid) { if ((*p_Vid = (VideoParameters *) calloc(1, sizeof(VideoParameters)))==NULL) no_mem_exit("alloc_img: p_Vid"); if (((*p_Vid)->old_slice = (OldSliceParams *) calloc(1, sizeof(OldSliceParams)))==NULL) no_mem_exit("alloc_img: p_Vid->old_slice"); if (((*p_Vid)->p_Dpb = (DecodedPictureBuffer*)calloc(1, sizeof(DecodedPictureBuffer)))==NULL) no_mem_exit("alloc_img: p_Vid->p_Dpb"); (*p_Vid)->p_Dpb->init_done = 0; (*p_Vid)->global_init_done = 0; #if (ENABLE_OUTPUT_TONEMAPPING) if (((*p_Vid)->seiToneMapping = (ToneMappingSEI*)calloc(1, sizeof(ToneMappingSEI)))==NULL) no_mem_exit("alloc_img: (*p_Vid)->seiToneMapping"); #endif } /*! *********************************************************************** * \brief * Allocate the Input structure * \par Output: * Input Parameters InputParameters *p_Vid *********************************************************************** */ static void alloc_params( InputParameters **p_Inp ) { if ((*p_Inp = (InputParameters *) calloc(1, sizeof(InputParameters)))==NULL) no_mem_exit("alloc_params: p_Inp"); } /*! *********************************************************************** * \brief * Allocate the Decoder Structure * \par Output: * Decoder Parameters *********************************************************************** */ DecoderParams *alloc_decoder() { DecoderParams *decoder = (DecoderParams *) calloc(1, sizeof(DecoderParams)); if (decoder) { alloc_img(&(decoder->p_Vid)); alloc_params(&(decoder->p_Inp)); #ifdef TRACE p_trace = 0; bitcounter = 0; #endif } return decoder; } /*! *********************************************************************** * \brief * Free the Image structure * \par Input: * Image Parameters VideoParameters *p_Vid *********************************************************************** */ void free_img( VideoParameters *p_Vid) { if (p_Vid != NULL) { free_mem_input(p_Vid); #if (ENABLE_OUTPUT_TONEMAPPING) if (p_Vid->seiToneMapping != NULL) { free (p_Vid->seiToneMapping); p_Vid->seiToneMapping = NULL; } #endif if (p_Vid->p_Dpb != NULL) { free (p_Vid->p_Dpb); p_Vid->p_Dpb = NULL; } if (p_Vid->old_slice != NULL) { free (p_Vid->old_slice); p_Vid->old_slice = NULL; } free (p_Vid); p_Vid = NULL; } } /*! *********************************************************************** * \brief * main function for TML decoder *********************************************************************** */ #if 0 int main(int argc, char **argv) { DecoderParams *p_Dec = alloc_decoder(); if (!p_Dec) return 1; Configure(p_Dec->p_Vid, p_Dec->p_Inp, argc, argv); initBitsFile(p_Dec->p_Vid, p_Dec->p_Inp->FileFormat); p_Dec->p_Vid->bitsfile->OpenBitsFile(p_Dec->p_Vid, p_Dec->p_Inp->infile); // Allocate Slice data struct malloc_slice(p_Dec->p_Inp, p_Dec->p_Vid); init_old_slice(p_Dec->p_Vid->old_slice); init(p_Dec->p_Vid); init_out_buffer(p_Dec->p_Vid); while (decode_one_frame(p_Dec->p_Vid) != EOS) ; free_slice(p_Dec->p_Vid->currentSlice); FmoFinit(p_Dec->p_Vid); free_global_buffers(p_Dec->p_Vid); flush_dpb(p_Dec->p_Vid); #if (PAIR_FIELDS_IN_OUTPUT) flush_pending_output(p_Dec->p_Vid, p_Dec->p_Vid->p_out); #endif p_Dec->p_Vid->bitsfile->CloseBitsFile(p_Dec->p_Vid); close(p_Dec->p_Vid->p_out); if (p_Dec->p_Vid->p_ref != -1) close(p_Dec->p_Vid->p_ref); #if TRACE fclose(p_trace); #endif ercClose(p_Dec->p_Vid, p_Dec->p_Vid->erc_errorVar); CleanUpPPS(p_Dec->p_Vid); free_dpb(p_Dec->p_Vid); uninit_out_buffer(p_Dec->p_Vid); free (p_Dec->p_Inp); free_img (p_Dec->p_Vid); free(p_Dec); return 0; } #endif /*! *********************************************************************** * \brief * Initilize some arrays *********************************************************************** */ void init(VideoParameters *p_Vid) //!< image parameters { int i; InputParameters *p_Inp = p_Vid->p_Inp; p_Vid->oldFrameSizeInMbs = -1; p_Vid->recovery_point = 0; p_Vid->recovery_point_found = 0; p_Vid->recovery_poc = 0x7fffffff; /* set to a max value */ p_Vid->number = 0; p_Vid->type = I_SLICE; p_Vid->dec_ref_pic_marking_buffer = NULL; p_Vid->dec_picture = NULL; // reference flag initialization for(i=0;i<17;++i) { p_Vid->ref_flag[i] = 1; } p_Vid->MbToSliceGroupMap = NULL; p_Vid->MapUnitToSliceGroupMap = NULL; p_Vid->LastAccessUnitExists = 0; p_Vid->NALUCount = 0; p_Vid->out_buffer = NULL; p_Vid->pending_output = NULL; p_Vid->pending_output_state = FRAME; p_Vid->recovery_flag = 0; #if (ENABLE_OUTPUT_TONEMAPPING) init_tone_mapping_sei(p_Vid->seiToneMapping); #endif } /*! *********************************************************************** * \brief * Initialize FREXT variables *********************************************************************** */ void init_frext(VideoParameters *p_Vid) //!< image parameters { //pel bitdepth init p_Vid->bitdepth_luma_qp_scale = 6 * (p_Vid->bitdepth_luma - 8); p_Vid->dc_pred_value_comp[0] = 1<<(p_Vid->bitdepth_luma - 1); p_Vid->max_pel_value_comp[0] = (1<bitdepth_luma) - 1; p_Vid->mb_size[IS_LUMA][0] = p_Vid->mb_size[IS_LUMA][1] = MB_BLOCK_SIZE; if (p_Vid->active_sps->chroma_format_idc != YUV400) { //for chrominance part p_Vid->bitdepth_chroma_qp_scale = 6 * (p_Vid->bitdepth_chroma - 8); p_Vid->dc_pred_value_comp[1] = (1 << (p_Vid->bitdepth_chroma - 1)); p_Vid->dc_pred_value_comp[2] = p_Vid->dc_pred_value_comp[1]; p_Vid->max_pel_value_comp[1] = (1 << p_Vid->bitdepth_chroma) - 1; p_Vid->max_pel_value_comp[2] = (1 << p_Vid->bitdepth_chroma) - 1; p_Vid->num_blk8x8_uv = (1 << p_Vid->active_sps->chroma_format_idc) & (~(0x1)); p_Vid->num_uv_blocks = (p_Vid->num_blk8x8_uv >> 1); p_Vid->num_cdc_coeff = (p_Vid->num_blk8x8_uv << 1); p_Vid->mb_size[IS_CHROMA][0] = p_Vid->mb_size[2][0] = p_Vid->mb_cr_size_x = (p_Vid->active_sps->chroma_format_idc==YUV420 || p_Vid->active_sps->chroma_format_idc==YUV422)? 8 : 16; p_Vid->mb_size[IS_CHROMA][1] = p_Vid->mb_size[2][1] = p_Vid->mb_cr_size_y = (p_Vid->active_sps->chroma_format_idc==YUV444 || p_Vid->active_sps->chroma_format_idc==YUV422)? 16 : 8; p_Vid->subpel_x = p_Vid->mb_cr_size_x == 8 ? 7 : 3; p_Vid->subpel_y = p_Vid->mb_cr_size_y == 8 ? 7 : 3; p_Vid->shiftpel_x = p_Vid->mb_cr_size_x == 8 ? 3 : 2; p_Vid->shiftpel_y = p_Vid->mb_cr_size_y == 8 ? 3 : 2; } else { p_Vid->bitdepth_chroma_qp_scale = 0; p_Vid->max_pel_value_comp[1] = 0; p_Vid->max_pel_value_comp[2] = 0; p_Vid->num_blk8x8_uv = 0; p_Vid->num_uv_blocks = 0; p_Vid->num_cdc_coeff = 0; p_Vid->mb_size[IS_CHROMA][0] = p_Vid->mb_size[2][0] = p_Vid->mb_cr_size_x = 0; p_Vid->mb_size[IS_CHROMA][1] = p_Vid->mb_size[2][1] = p_Vid->mb_cr_size_y = 0; p_Vid->subpel_x = 0; p_Vid->subpel_y = 0; p_Vid->shiftpel_x = 0; p_Vid->shiftpel_y = 0; } p_Vid->mb_size_blk[0][0] = p_Vid->mb_size_blk[0][1] = p_Vid->mb_size[0][0] >> 2; p_Vid->mb_size_blk[1][0] = p_Vid->mb_size_blk[2][0] = p_Vid->mb_size[1][0] >> 2; p_Vid->mb_size_blk[1][1] = p_Vid->mb_size_blk[2][1] = p_Vid->mb_size[1][1] >> 2; p_Vid->mb_size_shift[0][0] = p_Vid->mb_size_shift[0][1] = CeilLog2_sf (p_Vid->mb_size[0][0]); p_Vid->mb_size_shift[1][0] = p_Vid->mb_size_shift[2][0] = CeilLog2_sf (p_Vid->mb_size[1][0]); p_Vid->mb_size_shift[1][1] = p_Vid->mb_size_shift[2][1] = CeilLog2_sf (p_Vid->mb_size[1][1]); } /*! ************************************************************************ * \brief * Allocates a stand-alone partition structure. Structure should * be freed by FreePartition(); * data structures * * \par Input: * n: number of partitions in the array * \par return * pointer to DataPartition Structure, zero-initialized ************************************************************************ */ DataPartition *AllocPartition(int n) { DataPartition *partArr, *dataPart; int i; partArr = (DataPartition *) calloc(n, sizeof(DataPartition)); if (partArr == NULL) { snprintf(errortext, ET_SIZE, "AllocPartition: Memory allocation for Data Partition failed"); error(errortext, 100); } for (i=0; ibitstream = (Bitstream *) calloc(1, sizeof(Bitstream)); if (dataPart->bitstream == NULL) { snprintf(errortext, ET_SIZE, "AllocPartition: Memory allocation for Bitstream failed"); error(errortext, 100); } dataPart->bitstream->streamBuffer = 0; } return partArr; } /*! ************************************************************************ * \brief * Frees a partition structure (array). * * \par Input: * Partition to be freed, size of partition Array (Number of Partitions) * * \par return * None * * \note * n must be the same as for the corresponding call of AllocPartition ************************************************************************ */ void FreePartition (DataPartition *dp, int n) { int i; assert (dp != NULL); assert (dp->bitstream != NULL); //assert (dp->bitstream->streamBuffer != NULL); for (i=0; istreamBuffer); free (dp[i].bitstream); } free (dp); } /*! ************************************************************************ * \brief * Allocates the slice structure along with its dependent * data structures * * \par Input: * Input Parameters InputParameters *p_Inp, VideoParameters *p_Vid ************************************************************************ */ void malloc_slice(InputParameters *p_Inp, VideoParameters *p_Vid) { int memory_size = 0; Slice *currSlice; p_Vid->currentSlice = (Slice *) _aligned_malloc(sizeof(Slice), 32); if ( (currSlice = p_Vid->currentSlice) == NULL) { error("Memory allocation for Slice datastruct failed",100); } memset(p_Vid->currentSlice, 0, sizeof(Slice)); // p_Vid->currentSlice->rmpni_buffer=NULL; //! you don't know whether we do CABAC here, hence initialize CABAC anyway // if (p_Inp->symbol_mode == CABAC) // create all context models currSlice->mot_ctx = create_contexts_MotionInfo(); currSlice->tex_ctx = create_contexts_TextureInfo(); currSlice->max_part_nr = 3; //! assume data partitioning (worst case) for the following mallocs() currSlice->partArr = AllocPartition(currSlice->max_part_nr); currSlice->p_colocated = NULL; currSlice->coeff_ctr = -1; currSlice->pos = 0; } /*! ************************************************************************ * \brief * Memory frees of the Slice structure and of its dependent * data structures * * \par Input: * Input Parameters InputParameters *p_Inp, VideoParameters *p_Vid ************************************************************************ */ void free_slice(Slice *currSlice) { FreePartition (currSlice->partArr, 3); if (1) { // delete all context models delete_contexts_MotionInfo(currSlice->mot_ctx); delete_contexts_TextureInfo(currSlice->tex_ctx); } _aligned_free(currSlice); currSlice = NULL; } /*! ************************************************************************ * \brief * Dynamic memory allocation of frame size related global buffers * buffers are defined in global.h, allocated memory must be freed in * void free_global_buffers() * * \par Input: * Input Parameters InputParameters *p_Inp, Image Parameters VideoParameters *p_Vid * * \par Output: * Number of allocated bytes *********************************************************************** */ int init_global_buffers(VideoParameters *p_Vid) { int memory_size=0; int i; if (p_Vid->global_init_done) { free_global_buffers(p_Vid); } // allocate memory in structure p_Vid if( IS_INDEPENDENT(p_Vid) ) { for( i=0; imb_data_JV[i]) = (Macroblock *) calloc(p_Vid->FrameSizeInMbs, sizeof(Macroblock))) == NULL) no_mem_exit("init_global_buffers: p_Vid->mb_data"); } p_Vid->mb_data = NULL; } else { if(((p_Vid->mb_data) = (Macroblock *) calloc(p_Vid->FrameSizeInMbs, sizeof(Macroblock))) == NULL) no_mem_exit("init_global_buffers: p_Vid->mb_data"); } if(((p_Vid->intra_block) = (int*)calloc(p_Vid->FrameSizeInMbs, sizeof(int))) == NULL) no_mem_exit("init_global_buffers: p_Vid->intra_block"); p_Vid->PicPos = (h264_pic_position *)calloc(p_Vid->FrameSizeInMbs + 1, sizeof(h264_pic_position)); //! Helper array to access macroblock positions. We add 1 to also consider last MB. for (i = 0; i < (int) p_Vid->FrameSizeInMbs + 1;++i) { p_Vid->PicPos[i][0] = (i % p_Vid->PicWidthInMbs); p_Vid->PicPos[i][1] = (i / p_Vid->PicWidthInMbs); } memory_size += get_mem2D(&(p_Vid->ipredmode), 4*p_Vid->FrameHeightInMbs, 4*p_Vid->PicWidthInMbs); // CAVLC mem p_Vid->nz_coeff = (h264_nz_coefficient *)_aligned_malloc(p_Vid->FrameSizeInMbs*sizeof(h264_nz_coefficient), 32); memset(p_Vid->nz_coeff, 0, p_Vid->FrameSizeInMbs*sizeof(h264_nz_coefficient)); //memory_size += get_mem4D(&(p_Vid->nz_coeff), p_Vid->FrameSizeInMbs, 3, BLOCK_SIZE, BLOCK_SIZE); memory_size += get_mem2Dint(&(p_Vid->siblock), p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs); init_qp_process(p_Vid); p_Vid->global_init_done = 1; p_Vid->oldFrameSizeInMbs = p_Vid->FrameSizeInMbs; return (memory_size); } /*! ************************************************************************ * \brief * Free allocated memory of frame size related global buffers * buffers are defined in global.h, allocated memory is allocated in * int init_global_buffers() * * \par Input: * Input Parameters InputParameters *p_Inp, Image Parameters VideoParameters *p_Vid * * \par Output: * none * ************************************************************************ */ void free_global_buffers(VideoParameters *p_Vid) { // CAVLC free mem _aligned_free(p_Vid->nz_coeff); free_mem2Dint(p_Vid->siblock); // free mem, allocated for structure p_Vid if (p_Vid->mb_data != NULL) free(p_Vid->mb_data); free(p_Vid->PicPos); free (p_Vid->intra_block); free_mem2D(p_Vid->ipredmode); free_qp_matrices(p_Vid); p_Vid->global_init_done = 0; }