/* * H.265 video codec. * Copyright (c) 2013-2014 struktur AG, Dirk Farin * * This file is part of libde265. * * libde265 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * libde265 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libde265. If not, see . */ #ifndef DE265_IMAGE_H #define DE265_IMAGE_H #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #ifdef HAVE_STDBOOL_H #include #endif #include "libde265/de265.h" #include "libde265/sps.h" #include "libde265/pps.h" #include "libde265/motion.h" #include "libde265/threads.h" #include "libde265/slice.h" #include "libde265/nal.h" struct en265_encoder_context; enum PictureState { UnusedForReference, UsedForShortTermReference, UsedForLongTermReference }; /* TODO: At INTEGRITY_DERIVED_FROM_FAULTY_REFERENCE images, we can check the SEI hash, whether the output image is correct despite the faulty reference, and set the state back to correct. */ #define INTEGRITY_CORRECT 0 #define INTEGRITY_UNAVAILABLE_REFERENCE 1 #define INTEGRITY_NOT_DECODED 2 #define INTEGRITY_DECODING_ERRORS 3 #define INTEGRITY_DERIVED_FROM_FAULTY_REFERENCE 4 #define SEI_HASH_UNCHECKED 0 #define SEI_HASH_CORRECT 1 #define SEI_HASH_INCORRECT 2 #define TU_FLAG_NONZERO_COEFF (1<<7) #define TU_FLAG_SPLIT_TRANSFORM_MASK 0x1F #define DEBLOCK_FLAG_VERTI (1<<4) #define DEBLOCK_FLAG_HORIZ (1<<5) #define DEBLOCK_PB_EDGE_VERTI (1<<6) #define DEBLOCK_PB_EDGE_HORIZ (1<<7) #define DEBLOCK_BS_MASK 0x03 #define CTB_PROGRESS_NONE 0 #define CTB_PROGRESS_PREFILTER 1 #define CTB_PROGRESS_DEBLK_V 2 #define CTB_PROGRESS_DEBLK_H 3 #define CTB_PROGRESS_SAO 4 class decoder_context; template class MetaDataArray { public: MetaDataArray() { data=NULL; data_size=0; log2unitSize=0; width_in_units=0; height_in_units=0; } ~MetaDataArray() { free(data); } LIBDE265_CHECK_RESULT bool alloc(int w,int h, int _log2unitSize) { int size = w*h; if (size != data_size) { free(data); data = (DataUnit*)malloc(size * sizeof(DataUnit)); if (data == NULL) { data_size = 0; return false; } data_size = size; } width_in_units = w; height_in_units = h; log2unitSize = _log2unitSize; return data != NULL; } void clear() { if (data) memset(data, 0, sizeof(DataUnit) * data_size); } const DataUnit& get(int x,int y) const { int unitX = x>>log2unitSize; int unitY = y>>log2unitSize; assert(unitX >= 0 && unitX < width_in_units); assert(unitY >= 0 && unitY < height_in_units); return data[ unitX + unitY*width_in_units ]; } DataUnit& get(int x,int y) { int unitX = x>>log2unitSize; int unitY = y>>log2unitSize; assert(unitX >= 0 && unitX < width_in_units); assert(unitY >= 0 && unitY < height_in_units); return data[ unitX + unitY*width_in_units ]; } void set(int x,int y, const DataUnit& d) { int unitX = x>>log2unitSize; int unitY = y>>log2unitSize; assert(unitX >= 0 && unitX < width_in_units); assert(unitY >= 0 && unitY < height_in_units); data[ unitX + unitY*width_in_units ] = d; } DataUnit& operator[](int idx) { return data[idx]; } const DataUnit& operator[](int idx) const { return data[idx]; } int size() const { return data_size; } // private: DataUnit* data; int data_size; int log2unitSize; int width_in_units; int height_in_units; }; #define SET_CB_BLK(x,y,log2BlkWidth, Field,value) \ int cbX = x >> cb_info.log2unitSize; \ int cbY = y >> cb_info.log2unitSize; \ int width = 1 << (log2BlkWidth - cb_info.log2unitSize); \ for (int cby=cbY;cby> tu_info.log2unitSize; \ int tuY = y >> tu_info.log2unitSize; \ int width = 1 << (log2BlkWidth - tu_info.log2unitSize); \ for (int tuy=tuY;tuy sps, bool allocMetadata, decoder_context* dctx, //class encoder_context* ectx, de265_PTS pts, void* user_data, bool useCustomAllocFunctions); //de265_error alloc_encoder_data(const seq_parameter_set* sps); bool is_allocated() const { return pixels[0] != NULL; } void release(); void set_headers(std::shared_ptr _vps, std::shared_ptr _sps, std::shared_ptr _pps) { vps = _vps; sps = _sps; pps = _pps; } void fill_image(int y,int u,int v); de265_error copy_image(const de265_image* src); void copy_lines_from(const de265_image* src, int first, int end); void exchange_pixel_data_with(de265_image&); uint32_t get_ID() const { return ID; } /* */ uint8_t* get_image_plane(int cIdx) { return pixels[cIdx]; } const uint8_t* get_image_plane(int cIdx) const { return pixels[cIdx]; } void set_image_plane(int cIdx, uint8_t* mem, int stride, void *userdata); uint8_t* get_image_plane_at_pos(int cIdx, int xpos,int ypos) { int stride = get_image_stride(cIdx); return pixels[cIdx] + xpos + ypos*stride; } /// xpos;ypos in actual plane resolution template pixel_t* get_image_plane_at_pos_NEW(int cIdx, int xpos,int ypos) { int stride = get_image_stride(cIdx); return (pixel_t*)(pixels[cIdx] + (xpos + ypos*stride)*sizeof(pixel_t)); } const uint8_t* get_image_plane_at_pos(int cIdx, int xpos,int ypos) const { int stride = get_image_stride(cIdx); return pixels[cIdx] + xpos + ypos*stride; } void* get_image_plane_at_pos_any_depth(int cIdx, int xpos,int ypos) { int stride = get_image_stride(cIdx); return pixels[cIdx] + ((xpos + ypos*stride) << bpp_shift[cIdx]); } const void* get_image_plane_at_pos_any_depth(int cIdx, int xpos,int ypos) const { int stride = get_image_stride(cIdx); return pixels[cIdx] + ((xpos + ypos*stride) << bpp_shift[cIdx]); } /* Number of pixels in one row (not number of bytes). */ int get_image_stride(int cIdx) const { if (cIdx==0) return stride; else return chroma_stride; } int get_luma_stride() const { return stride; } int get_chroma_stride() const { return chroma_stride; } int get_width (int cIdx=0) const { return cIdx==0 ? width : chroma_width; } int get_height(int cIdx=0) const { return cIdx==0 ? height : chroma_height; } enum de265_chroma get_chroma_format() const { return chroma_format; } int get_bit_depth(int cIdx) const { if (cIdx==0) return sps->BitDepth_Y; else return sps->BitDepth_C; } int get_bytes_per_pixel(int cIdx) const { return (get_bit_depth(cIdx)+7)/8; } bool high_bit_depth(int cIdx) const { return get_bit_depth(cIdx)>8; } bool can_be_released() const { return PicOutputFlag==false && PicState==UnusedForReference; } void add_slice_segment_header(slice_segment_header* shdr) { shdr->slice_index = slices.size(); slices.push_back(shdr); } bool available_zscan(int xCurr,int yCurr, int xN,int yN) const; bool available_pred_blk(int xC,int yC, int nCbS, int xP, int yP, int nPbW, int nPbH, int partIdx, int xN,int yN) const; static de265_image_allocation default_image_allocation; void printBlk(const char* title, int x0,int y0,int blkSize,int cIdx) const { ::printBlk(title, get_image_plane_at_pos(cIdx,x0,y0), blkSize, get_image_stride(cIdx)); } private: uint32_t ID; static uint32_t s_next_image_ID; uint8_t* pixels[3]; uint8_t bpp_shift[3]; // 0 for 8 bit, 1 for 16 bit enum de265_chroma chroma_format; int width, height; // size in luma pixels int chroma_width, chroma_height; int stride, chroma_stride; public: uint8_t BitDepth_Y, BitDepth_C; uint8_t SubWidthC, SubHeightC; std::vector slices; public: // --- conformance cropping window --- uint8_t* pixels_confwin[3]; // pointer to pixels in the conformance window int width_confwin, height_confwin; int chroma_width_confwin, chroma_height_confwin; // --- decoding info --- // If PicOutputFlag==false && PicState==UnusedForReference, image buffer is free. int picture_order_cnt_lsb; int PicOrderCntVal; enum PictureState PicState; bool PicOutputFlag; int32_t removed_at_picture_id; const video_parameter_set& get_vps() const { return *vps; } const seq_parameter_set& get_sps() const { return *sps; } const pic_parameter_set& get_pps() const { return *pps; } bool has_vps() const { return (bool)vps; } bool has_sps() const { return (bool)sps; } bool has_pps() const { return (bool)pps; } std::shared_ptr get_shared_sps() { return sps; } //std::shared_ptr get_shared_sps() const { return sps; } //std::shared_ptr get_shared_pps() const { return pps; } decoder_context* decctx; //class encoder_context* encctx; int number_of_ctbs() const { return ctb_info.size(); } private: // The image also keeps a reference to VPS/SPS/PPS, because when decoding is delayed, // the currently active parameter sets in the decctx might already have been replaced // with new parameters. std::shared_ptr vps; std::shared_ptr sps; // the SPS used for decoding this image std::shared_ptr pps; // the PPS used for decoding this image MetaDataArray ctb_info; MetaDataArray cb_info; MetaDataArray pb_info; MetaDataArray intraPredMode; MetaDataArray intraPredModeC; MetaDataArray tu_info; MetaDataArray deblk_info; public: // --- meta information --- de265_PTS pts; void* user_data; void* plane_user_data[3]; // this is logically attached to the pixel data pointers de265_image_allocation image_allocation_functions; // the functions used for memory allocation /* void (*encoder_image_release_func)(en265_encoder_context*, de265_image*, void* userdata); */ uint8_t integrity; /* Whether an error occured while the image was decoded. When generated, this is initialized to INTEGRITY_CORRECT, and changed on decoding errors. */ bool sei_hash_check_result; nal_header nal_hdr; // --- multi core --- de265_progress_lock* ctb_progress; // ctb_info_size void mark_all_CTB_progress(int progress) { for (int i=0;i> tu_info.log2unitSize; const int tuY = y >> tu_info.log2unitSize; const int width = 1 << (log2TrafoSize - tu_info.log2unitSize); for (int tuy=tuY;tuy>sps->Log2MinPUSize) + (y0>>sps->Log2MinPUSize)*sps->PicWidthInMinPUs; for (int y=0;yPicWidthInMinPUs); assert(y < sps->PicHeightInMinPUs); int idx = PUidx + x + y*intraPredMode.width_in_units; assert(idx>sps->Log2MinPUSize) + (y0>>sps->Log2MinPUSize)*sps->PicWidthInMinPUs; for (int y=0;yPicWidthInMinPUs); assert(yPicHeightInMinPUs); int idx = PUidx + x + y*intraPredModeC.width_in_units; assert(idx= 0 && idx < slices.size(); } slice_segment_header* get_SliceHeader(int x, int y) { int idx = get_SliceHeaderIndex(x,y); if (idx >= slices.size()) { return NULL; } return slices[idx]; } slice_segment_header* get_SliceHeaderCtb(int ctbX, int ctbY) { int idx = get_SliceHeaderIndexCtb(ctbX,ctbY); if (idx >= slices.size()) { return NULL; } return slices[idx]; } const slice_segment_header* get_SliceHeaderCtb(int ctbX, int ctbY) const { int idx = get_SliceHeaderIndexCtb(ctbX,ctbY); if (idx >= slices.size()) { return NULL; } return slices[idx]; } void set_sao_info(int ctbX,int ctbY,const sao_info* saoinfo) { sao_info* sao = &ctb_info[ctbX + ctbY*ctb_info.width_in_units].saoInfo; memcpy(sao, saoinfo, sizeof(sao_info)); } const sao_info* get_sao_info(int ctbX,int ctbY) const { return &ctb_info[ctbX + ctbY*ctb_info.width_in_units].saoInfo; } void set_CtbDeblockFlag(int ctbX, int ctbY, bool flag) { int idx = ctbX + ctbY*ctb_info.width_in_units; ctb_info[idx].deblock = flag; } bool get_CtbDeblockFlag(int ctbX, int ctbY) const { return ctb_info[ctbX + ctbY*ctb_info.width_in_units].deblock; } bool get_CTB_has_pcm_or_cu_transquant_bypass(int ctbX,int ctbY) const { int idx = ctbX + ctbY*ctb_info.width_in_units; return ctb_info[idx].has_pcm_or_cu_transquant_bypass; } // --- DEBLK metadata access --- int get_deblk_width() const { return deblk_info.width_in_units; } int get_deblk_height() const { return deblk_info.height_in_units; } void set_deblk_flags(int x0,int y0, uint8_t flags) { const int xd = x0/4; const int yd = y0/4; if (xd