diff options
Diffstat (limited to 'Src/h264dec/ldecod/src/output.c')
-rw-r--r-- | Src/h264dec/ldecod/src/output.c | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/Src/h264dec/ldecod/src/output.c b/Src/h264dec/ldecod/src/output.c new file mode 100644 index 00000000..74576af0 --- /dev/null +++ b/Src/h264dec/ldecod/src/output.c @@ -0,0 +1,599 @@ + +/*! + ************************************************************************ + * \file output.c + * + * \brief + * Output an image and Trance support + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring <suehring@hhi.de> + ************************************************************************ + */ + +#include "contributors.h" + +#include "global.h" +#include "mbuffer.h" +#include "image.h" +#include "memalloc.h" +#include "sei.h" + +static void write_out_picture(VideoParameters *p_Vid, StorablePicture *p); + + +#if (PAIR_FIELDS_IN_OUTPUT) + +void clear_picture(VideoParameters *p_Vid, StorablePicture *p); + +/*! + ************************************************************************ + * \brief + * output the pending frame buffer + * \param p_out + * Output file + ************************************************************************ + */ +void flush_pending_output(VideoParameters *p_Vid) +{ + if (p_Vid->pending_output_state != FRAME) + { + write_out_picture(p_Vid, p_Vid->pending_output); + } + + if (p_Vid->pending_output->imgY) + { + free_mem2Dpel (p_Vid->pending_output->imgY); + p_Vid->pending_output->imgY=NULL; + } + if (p_Vid->pending_output->imgUV) + { + free_mem3Dpel (p_Vid->pending_output->imgUV); + p_Vid->pending_output->imgUV=NULL; + } + + p_Vid->pending_output_state = FRAME; +} + + +/*! + ************************************************************************ + * \brief + * Writes out a storable picture + * If the picture is a field, the output buffers the picture and tries + * to pair it with the next field. + * \param p + * Picture to be written + * \param p_out + * Output file + ************************************************************************ + */ +void write_picture(VideoParameters *p_Vid, StorablePicture *p, int real_structure) +{ + int i, add; + + if (real_structure==FRAME) + { + flush_pending_output(p_Vid); + write_out_picture(p_Vid, p); + return; + } + if (real_structure == p_Vid->pending_output_state) + { + flush_pending_output(p_Vid); + write_picture(p_Vid, p, real_structure); + return; + } + + if (p_Vid->pending_output_state == FRAME) + { + p_Vid->pending_output->size_x = p->size_x; + p_Vid->pending_output->size_y = p->size_y; + p_Vid->pending_output->size_x_cr = p->size_x_cr; + p_Vid->pending_output->size_y_cr = p->size_y_cr; + p_Vid->pending_output->chroma_format_idc = p->chroma_format_idc; + + p_Vid->pending_output->frame_mbs_only_flag = p->frame_mbs_only_flag; + p_Vid->pending_output->frame_cropping_flag = p->frame_cropping_flag; + if (p_Vid->pending_output->frame_cropping_flag) + { + p_Vid->pending_output->frame_cropping_rect_left_offset = p->frame_cropping_rect_left_offset; + p_Vid->pending_output->frame_cropping_rect_right_offset = p->frame_cropping_rect_right_offset; + p_Vid->pending_output->frame_cropping_rect_top_offset = p->frame_cropping_rect_top_offset; + p_Vid->pending_output->frame_cropping_rect_bottom_offset = p->frame_cropping_rect_bottom_offset; + } + + get_mem2Dpel (&(p_Vid->pending_output->imgY), p_Vid->pending_output->size_y, p_Vid->pending_output->size_x); + get_mem3Dpel (&(p_Vid->pending_output->imgUV), 2, p_Vid->pending_output->size_y_cr, p_Vid->pending_output->size_x_cr); + + clear_picture(p_Vid, p_Vid->pending_output); + + // copy first field + if (real_structure == TOP_FIELD) + { + add = 0; + } + else + { + add = 1; + } + + for (i=0; i<p_Vid->pending_output->size_y; i+=2) + { + memcpy(p_Vid->pending_output->imgY[(i+add)], p->imgY[(i+add)], p->size_x * sizeof(imgpel)); + } + for (i=0; i<p_Vid->pending_output->size_y_cr; i+=2) + { + memcpy(p_Vid->pending_output->imgUV[0][(i+add)], p->imgUV[0][(i+add)], p->size_x_cr * sizeof(imgpel)); + memcpy(p_Vid->pending_output->imgUV[1][(i+add)], p->imgUV[1][(i+add)], p->size_x_cr * sizeof(imgpel)); + } + p_Vid->pending_output_state = real_structure; + } + else + { + if ( (p_Vid->pending_output->size_x!=p->size_x) || (p_Vid->pending_output->size_y!= p->size_y) + || (p_Vid->pending_output->frame_mbs_only_flag != p->frame_mbs_only_flag) + || (p_Vid->pending_output->frame_cropping_flag != p->frame_cropping_flag) + || ( p_Vid->pending_output->frame_cropping_flag && + ( (p_Vid->pending_output->frame_cropping_rect_left_offset != p->frame_cropping_rect_left_offset) + ||(p_Vid->pending_output->frame_cropping_rect_right_offset != p->frame_cropping_rect_right_offset) + ||(p_Vid->pending_output->frame_cropping_rect_top_offset != p->frame_cropping_rect_top_offset) + ||(p_Vid->pending_output->frame_cropping_rect_bottom_offset != p->frame_cropping_rect_bottom_offset) + ) + ) + ) + { + flush_pending_output(p_Vid); + write_picture (p_Vid, p, real_structure); + return; + } + // copy second field + if (real_structure == TOP_FIELD) + { + add = 0; + } + else + { + add = 1; + } + + for (i=0; i<p_Vid->pending_output->size_y; i+=2) + { + memcpy(p_Vid->pending_output->imgY[(i+add)], p->imgY[(i+add)], p->size_x * sizeof(imgpel)); + } + for (i=0; i<p_Vid->pending_output->size_y_cr; i+=2) + { + memcpy(p_Vid->pending_output->imgUV[0][(i+add)], p->imgUV[0][(i+add)], p->size_x_cr * sizeof(imgpel)); + memcpy(p_Vid->pending_output->imgUV[1][(i+add)], p->imgUV[1][(i+add)], p->size_x_cr * sizeof(imgpel)); + } + + p_Vid->pending_output->time_code = p->time_code; + flush_pending_output(p_Vid); + } +} + +#else + +/*! + ************************************************************************ + * \brief + * Writes out a storable picture without doing any output modifications + * + * \param p_Vid + * image decoding parameters for current picture + * \param p + * Picture to be written + * \param p_out + * Output file + * \param real_structure + * real picture structure + ************************************************************************ + */ +static void write_picture(VideoParameters *p_Vid, StorablePicture *p, int real_structure) +{ + write_out_picture(p_Vid, p); +} + + +#endif + +/*! +************************************************************************ +* \brief +* Writes out a storable picture +* +* \param p_Vid +* image decoding parameters for current picture +* \param p +* Picture to be written +* \param p_out +* Output file +************************************************************************ +*/ +static void write_out_picture(VideoParameters *p_Vid, StorablePicture *p) +{ +#if 0 + InputParameters *p_Inp = p_Vid->p_Inp; + + static const int SubWidthC [4]= { 1, 2, 2, 1}; + static const int SubHeightC [4]= { 1, 2, 1, 1}; + + int crop_left, crop_right, crop_top, crop_bottom; + int symbol_size_in_bytes = (p_Vid->pic_unit_bitsize_on_disk >> 3); + Boolean rgb_output = (Boolean) (p_Vid->active_sps->vui_seq_parameters.matrix_coefficients==0); + unsigned char *buf; + + int ret; + + if (p->non_existing) + return; + + printf("*** Outputting poc %d, frame_num %d, frame_poc %d, pic_num %d\n", p->poc, p->frame_num, p->frame_poc, p->pic_num); + +#if (ENABLE_OUTPUT_TONEMAPPING) + // note: this tone-mapping is working for RGB format only. Sharp + if (p->seiHasTone_mapping && rgb_output) + { + //printf("output frame %d with tone model id %d\n", p->frame_num, p->tone_mapping_model_id); + symbol_size_in_bytes = (p->tonemapped_bit_depth>8)? 2 : 1; + tone_map(p->imgY, p->tone_mapping_lut, p->size_x, p->size_y); + tone_map(p->imgUV[0], p->tone_mapping_lut, p->size_x_cr, p->size_y_cr); + tone_map(p->imgUV[1], p->tone_mapping_lut, p->size_x_cr, p->size_y_cr); + } +#endif + + if (p->frame_cropping_flag) + { + crop_left = SubWidthC[p->chroma_format_idc] * p->frame_cropping_rect_left_offset; + crop_right = SubWidthC[p->chroma_format_idc] * p->frame_cropping_rect_right_offset; + crop_top = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_top_offset; + crop_bottom = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + + //printf ("write frame size: %dx%d\n", p->size_x-crop_left-crop_right,p->size_y-crop_top-crop_bottom ); + initOutput(p_Vid, symbol_size_in_bytes); + + // KS: this buffer should actually be allocated only once, but this is still much faster than the previous version + buf = malloc (p->size_x*p->size_y*symbol_size_in_bytes); + if (NULL==buf) + { + no_mem_exit("write_out_picture: buf"); + } + + if(rgb_output) + { + crop_left = p->frame_cropping_rect_left_offset; + crop_right = p->frame_cropping_rect_right_offset; + crop_top = ( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_top_offset; + crop_bottom = ( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_bottom_offset; + + p_Vid->img2buf (p->imgUV[1], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to RGB file", 500); + } + + if (p->frame_cropping_flag) + { + crop_left = SubWidthC[p->chroma_format_idc] * p->frame_cropping_rect_left_offset; + crop_right = SubWidthC[p->chroma_format_idc] * p->frame_cropping_rect_right_offset; + crop_top = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_top_offset; + crop_bottom = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + } + // write Y + p_Vid->img2buf (p->imgY, buf, p->size_x, p->size_y, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y-crop_bottom-crop_top)*(p->size_x-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y-crop_bottom-crop_top)*(p->size_x-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + + if (p->chroma_format_idc!=YUV400) + { + crop_left = p->frame_cropping_rect_left_offset; + crop_right = p->frame_cropping_rect_right_offset; + crop_top = ( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_top_offset; + crop_bottom = ( 2 - p->frame_mbs_only_flag ) * p->frame_cropping_rect_bottom_offset; + + p_Vid->img2buf (p->imgUV[0], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)* symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)* symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + if (!rgb_output) + { + p_Vid->img2buf (p->imgUV[1], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + } + } + else + { + if (p_Inp->write_uv) + { + int i,j; + imgpel cr_val = (imgpel) (1<<(p_Vid->bitdepth_luma - 1)); + + get_mem3Dpel (&(p->imgUV), 1, p->size_y/2, p->size_x/2); + for (j=0; j<p->size_y/2; j++) + for (i=0; i<p->size_x/2; i++) + p->imgUV[0][j][i]=cr_val; + + // fake out U=V=128 to make a YUV 4:2:0 stream + p_Vid->img2buf (p->imgUV[0], buf, p->size_x/2, p->size_y/2, symbol_size_in_bytes, crop_left/2, crop_right/2, crop_top/2, crop_bottom/2); + + ret = write(p_out, buf, symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2 ); + if (ret != (symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + ret = write(p_out, buf, symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2 ); + if (ret != (symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + + free_mem3Dpel(p->imgUV); + p->imgUV=NULL; + } + } + + free(buf); +#endif + if (p) + { + p->retain_count++; + out_storable_picture_add(p_Vid, p); + free_storable_picture(p_Vid, p); // release the reference we added above (out_storable_picture will add its own) + } +// fsync(p_out); +} + +/*! + ************************************************************************ + * \brief + * Initialize output buffer for direct output + ************************************************************************ + */ +void init_out_buffer(VideoParameters *p_Vid) +{ + p_Vid->out_buffer = alloc_frame_store(); + +#if (PAIR_FIELDS_IN_OUTPUT) + p_Vid->pending_output = calloc (sizeof(StorablePicture), 1); + if (NULL==p_Vid->pending_output) no_mem_exit("init_out_buffer"); + p_Vid->pending_output->imgUV = NULL; + p_Vid->pending_output->imgY = NULL; +#endif +} + +/*! + ************************************************************************ + * \brief + * Uninitialize output buffer for direct output + ************************************************************************ + */ +void uninit_out_buffer(VideoParameters *p_Vid) +{ + free_frame_store(p_Vid, p_Vid->out_buffer); + p_Vid->out_buffer=NULL; +#if (PAIR_FIELDS_IN_OUTPUT) + flush_pending_output(p_Vid); + free (p_Vid->pending_output); +#endif +} + +/*! + ************************************************************************ + * \brief + * Initialize picture memory with (Y:0,U:128,V:128) + ************************************************************************ + */ +void clear_picture(VideoParameters *p_Vid, StorablePicture *p) +{ + int i,j; + + for(i=0;i<p->size_y;i++) + { + for (j=0; j<p->size_x; j++) + p->imgY->img[i][j] = (imgpel) p_Vid->dc_pred_value_comp[0]; + } + for(i=0;i<p->size_y_cr;i++) + { + for (j=0; j<p->size_x_cr; j++) + p->imgUV[0]->img[i][j] = (imgpel) p_Vid->dc_pred_value_comp[1]; + } + for(i=0;i<p->size_y_cr;i++) + { + for (j=0; j<p->size_x_cr; j++) + p->imgUV[1]->img[i][j] = (imgpel) p_Vid->dc_pred_value_comp[2]; + } +} + +/*! + ************************************************************************ + * \brief + * Write out not paired direct output fields. A second empty field is generated + * and combined into the frame buffer. + * + * \param p_Vid + * image decoding parameters for current picture + * \param fs + * FrameStore that contains a single field + * \param p_out + * Output file + ************************************************************************ + */ +static void write_unpaired_field(VideoParameters *p_Vid, FrameStore* fs) +{ + StorablePicture *p; + assert (fs->is_used<3); + + if(fs->is_used & 0x01) + { + // we have a top field + // construct an empty bottom field + p = fs->top_field; + fs->bottom_field = alloc_storable_picture(p_Vid, BOTTOM_FIELD, p->size_x, 2*p->size_y, p->size_x_cr, 2*p->size_y_cr); + fs->bottom_field->chroma_format_idc = p->chroma_format_idc; + clear_picture(p_Vid, fs->bottom_field); + dpb_combine_field_yuv(p_Vid, fs); + write_picture (p_Vid, fs->frame, TOP_FIELD); + } + + if(fs->is_used & 0x02) + { + // we have a bottom field + // construct an empty top field + p = fs->bottom_field; + fs->top_field = alloc_storable_picture(p_Vid, TOP_FIELD, p->size_x, 2*p->size_y, p->size_x_cr, 2*p->size_y_cr); + fs->top_field->chroma_format_idc = p->chroma_format_idc; + clear_picture(p_Vid, fs->top_field); + fs ->top_field->frame_cropping_flag = fs->bottom_field->frame_cropping_flag; + if(fs ->top_field->frame_cropping_flag) + { + fs ->top_field->frame_cropping_rect_top_offset = fs->bottom_field->frame_cropping_rect_top_offset; + fs ->top_field->frame_cropping_rect_bottom_offset = fs->bottom_field->frame_cropping_rect_bottom_offset; + fs ->top_field->frame_cropping_rect_left_offset = fs->bottom_field->frame_cropping_rect_left_offset; + fs ->top_field->frame_cropping_rect_right_offset = fs->bottom_field->frame_cropping_rect_right_offset; + } + dpb_combine_field_yuv(p_Vid, fs); + write_picture (p_Vid, fs->frame, BOTTOM_FIELD); + } + + fs->is_used = 3; +} + +/*! + ************************************************************************ + * \brief + * Write out unpaired fields from output buffer. + * + * \param p_Vid + * image decoding parameters for current picture + * \param p_out + * Output file + ************************************************************************ + */ +static void flush_direct_output(VideoParameters *p_Vid) +{ + write_unpaired_field(p_Vid, p_Vid->out_buffer); + + free_storable_picture(p_Vid, p_Vid->out_buffer->frame); + p_Vid->out_buffer->frame = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->top_field); + p_Vid->out_buffer->top_field = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->bottom_field); + p_Vid->out_buffer->bottom_field = NULL; + p_Vid->out_buffer->is_used = 0; +} + + +/*! + ************************************************************************ + * \brief + * Write a frame (from FrameStore) + * + * \param p_Vid + * image decoding parameters for current picture + * \param fs + * FrameStore containing the frame + * \param p_out + * Output file + ************************************************************************ + */ +void write_stored_frame( VideoParameters *p_Vid, FrameStore *fs) +{ + // make sure no direct output field is pending + flush_direct_output(p_Vid); + + if (fs->is_used<3) + { + write_unpaired_field(p_Vid, fs); + } + else + { + if (fs->recovery_frame) + p_Vid->recovery_flag = 1; + if ((!p_Vid->non_conforming_stream) || p_Vid->recovery_flag) + write_picture(p_Vid, fs->frame, FRAME); + } + + fs->is_output = 1; +} + +/*! + ************************************************************************ + * \brief + * Directly output a picture without storing it in the DPB. Fields + * are buffered before they are written to the file. + * + * \param p_Vid + * image decoding parameters for current picture + * \param p + * Picture for output + * \param p_out + * Output file + ************************************************************************ + */ +void direct_output(VideoParameters *p_Vid, StorablePicture *p) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + if (p->structure==FRAME) + { + // we have a frame (or complementary field pair) + // so output it directly + flush_direct_output(p_Vid); + write_picture (p_Vid, p, FRAME); + free_storable_picture(p_Vid, p); + return; + } + + if (p->structure == TOP_FIELD) + { + if (p_Vid->out_buffer->is_used &1) + flush_direct_output(p_Vid); + p_Vid->out_buffer->top_field = p; + p_Vid->out_buffer->is_used |= 1; + } + + if (p->structure == BOTTOM_FIELD) + { + if (p_Vid->out_buffer->is_used &2) + flush_direct_output(p_Vid); + p_Vid->out_buffer->bottom_field = p; + p_Vid->out_buffer->is_used |= 2; + } + + if (p_Vid->out_buffer->is_used == 3) + { + // we have both fields, so output them + dpb_combine_field_yuv(p_Vid, p_Vid->out_buffer); + p_Vid->out_buffer->frame->time_code = p->time_code; + write_picture (p_Vid, p_Vid->out_buffer->frame, FRAME); + + free_storable_picture(p_Vid, p_Vid->out_buffer->frame); + p_Vid->out_buffer->frame = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->top_field); + p_Vid->out_buffer->top_field = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->bottom_field); + p_Vid->out_buffer->bottom_field = NULL; + p_Vid->out_buffer->is_used = 0; + } +} + |