blob: b7337f19791e7ad5c122d0c71d604540a52f48f4 [file] [log] [blame]
/*!
**************************************************************************************
* \file
* parset.c
* \brief
* Picture and Sequence Parameter set generation and handling
* \date 25 November 2002
* \author
* Main contributors (see contributors.h for copyright, address and affiliation details)
* - Stephan Wenger <stewe@cs.tu-berlin.de>
*
**************************************************************************************
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#include "global.h"
#include "contributors.h"
#include "mbuffer.h"
#include "parset.h"
#include "vlc.h"
// Local helpers
static int IdentifyProfile(void);
static int IdentifyLevel(void);
static int GenerateVUISequenceParameters(Bitstream *bitstream);
extern ColocatedParams *Co_located;
pic_parameter_set_rbsp_t *PicParSet[MAXPPS];
static const byte ZZ_SCAN[16] =
{ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
};
static const byte ZZ_SCAN8[64] =
{ 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};
/*!
*************************************************************************************
* \brief
* generates a sequence and picture parameter set and stores these in global
* active_sps and active_pps
*
* \return
* A NALU containing the Sequence ParameterSet
*
*************************************************************************************
*/
void GenerateParameterSets (void)
{
int i;
seq_parameter_set_rbsp_t *sps = NULL;
sps = AllocSPS();
for (i=0; i<MAXPPS; i++)
{
PicParSet[i] = NULL;
}
GenerateSequenceParameterSet(sps, 0);
if (input->GenerateMultiplePPS)
{
PicParSet[0] = AllocPPS();
PicParSet[1] = AllocPPS();
PicParSet[2] = AllocPPS();
if (sps->profile_idc >= FREXT_HP)
{
GeneratePictureParameterSet( PicParSet[0], sps, 0, 0, 0, input->cb_qp_index_offset, input->cr_qp_index_offset);
GeneratePictureParameterSet( PicParSet[1], sps, 1, 1, 1, input->cb_qp_index_offset, input->cr_qp_index_offset);
GeneratePictureParameterSet( PicParSet[2], sps, 2, 1, 2, input->cb_qp_index_offset, input->cr_qp_index_offset);
}
else
{
GeneratePictureParameterSet( PicParSet[0], sps, 0, 0, 0, input->chroma_qp_index_offset, 0);
GeneratePictureParameterSet( PicParSet[1], sps, 1, 1, 1, input->chroma_qp_index_offset, 0);
GeneratePictureParameterSet( PicParSet[2], sps, 2, 1, 2, input->chroma_qp_index_offset, 0);
}
}
else
{
PicParSet[0] = AllocPPS();
if (sps->profile_idc >= FREXT_HP)
GeneratePictureParameterSet( PicParSet[0], sps, 0, input->WeightedPrediction, input->WeightedBiprediction,
input->cb_qp_index_offset, input->cr_qp_index_offset);
else
GeneratePictureParameterSet( PicParSet[0], sps, 0, input->WeightedPrediction, input->WeightedBiprediction,
input->chroma_qp_index_offset, 0);
}
active_sps = sps;
active_pps = PicParSet[0];
}
/*!
*************************************************************************************
* \brief
* frees global parameter sets active_sps and active_pps
*
* \return
* A NALU containing the Sequence ParameterSet
*
*************************************************************************************
*/
void FreeParameterSets (void)
{
int i;
for (i=0; i<MAXPPS; i++)
{
if ( NULL != PicParSet[i])
{
FreePPS(PicParSet[i]);
PicParSet[i] = NULL;
}
}
FreeSPS (active_sps);
}
/*!
*************************************************************************************
* \brief
* int GenerateSeq_parameter_set_NALU (void);
*
* \note
* Uses the global variables through GenerateSequenceParameterSet()
* and GeneratePictureParameterSet
*
* \return
* A NALU containing the Sequence ParameterSet
*
*************************************************************************************
*/
NALU_t *GenerateSeq_parameter_set_NALU (void)
{
NALU_t *n = AllocNALU(64000);
int RBSPlen = 0;
int NALUlen;
byte rbsp[MAXRBSPSIZE];
RBSPlen = GenerateSeq_parameter_set_rbsp (active_sps, rbsp);
NALUlen = RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_SPS, NALU_PRIORITY_HIGHEST, 0, 1);
n->startcodeprefix_len = 4;
return n;
}
/*!
*************************************************************************************
* \brief
* NALU_t *GeneratePic_parameter_set_NALU (int PPS_id);
*
* \note
* Uses the global variables through GenerateSequenceParameterSet()
* and GeneratePictureParameterSet
*
* \return
* A NALU containing the Picture Parameter Set
*
*************************************************************************************
*/
NALU_t *GeneratePic_parameter_set_NALU(int PPS_id)
{
NALU_t *n = AllocNALU(64000);
int RBSPlen = 0;
int NALUlen;
byte rbsp[MAXRBSPSIZE];
RBSPlen = GeneratePic_parameter_set_rbsp (PicParSet[PPS_id], rbsp);
NALUlen = RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_PPS, NALU_PRIORITY_HIGHEST, 0, 1);
n->startcodeprefix_len = 4;
return n;
}
/*!
************************************************************************
* \brief
* GenerateSequenceParameterSet: extracts info from global variables and
* generates sequence parameter set structure
*
* \par
* Function reads all kinds of values from several global variables,
* including input-> and image-> and fills in the sps. Many
* values are current hard-coded to defaults.
*
************************************************************************
*/
void GenerateSequenceParameterSet( seq_parameter_set_rbsp_t *sps, //!< Sequence Parameter Set to be filled
int SPS_id //!< SPS ID
)
{
unsigned i;
int SubWidthC [4]= { 1, 2, 2, 1};
int SubHeightC [4]= { 1, 2, 1, 1};
int frext_profile = ((IdentifyProfile()==FREXT_HP) ||
(IdentifyProfile()==FREXT_Hi10P) ||
(IdentifyProfile()==FREXT_Hi422) ||
(IdentifyProfile()==FREXT_Hi444));
// *************************************************************************
// Sequence Parameter Set
// *************************************************************************
assert (sps != NULL);
// Profile and Level should be calculated using the info from the config
// file. Calculation is hidden in IndetifyProfile() and IdentifyLevel()
sps->profile_idc = IdentifyProfile();
sps->level_idc = IdentifyLevel();
// needs to be set according to profile
sps->constrained_set0_flag = FALSE;
sps->constrained_set1_flag = FALSE;
sps->constrained_set2_flag = FALSE;
if ( (sps->level_idc == 9) && (sps->profile_idc < FREXT_HP) ) // Level 1.b
{
sps->constrained_set3_flag = TRUE;
sps->level_idc = 11;
}
else
{
sps->constrained_set3_flag = FALSE;
}
// Parameter Set ID hard coded to zero
sps->seq_parameter_set_id = 0;
// Fidelity Range Extensions stuff
sps->bit_depth_luma_minus8 = input->BitDepthLuma - 8;
sps->bit_depth_chroma_minus8 = input->BitDepthChroma - 8;
img->lossless_qpprime_flag = input->lossless_qpprime_y_zero_flag & (sps->profile_idc==FREXT_Hi444);
//! POC stuff:
//! The following values are hard-coded in init_poc(). Apparently,
//! the poc implementation covers only a subset of the poc functionality.
//! Here, the same subset is implemented. Changes in the POC stuff have
//! also to be reflected here
sps->log2_max_frame_num_minus4 = log2_max_frame_num_minus4;
sps->log2_max_pic_order_cnt_lsb_minus4 = log2_max_pic_order_cnt_lsb_minus4;
sps->pic_order_cnt_type = input->pic_order_cnt_type;
sps->num_ref_frames_in_pic_order_cnt_cycle = img->num_ref_frames_in_pic_order_cnt_cycle;
sps->delta_pic_order_always_zero_flag = img->delta_pic_order_always_zero_flag;
sps->offset_for_non_ref_pic = img->offset_for_non_ref_pic;
sps->offset_for_top_to_bottom_field = img->offset_for_top_to_bottom_field;
for (i=0; i<img->num_ref_frames_in_pic_order_cnt_cycle; i++)
{
sps->offset_for_ref_frame[i] = img->offset_for_ref_frame[i];
}
// End of POC stuff
// Number of Reference Frames
sps->num_ref_frames = input->num_ref_frames;
//required_frame_num_update_behaviour_flag hardcoded to zero
sps->gaps_in_frame_num_value_allowed_flag = FALSE; // double check
sps->frame_mbs_only_flag = (Boolean) !(input->PicInterlace || input->MbInterlace);
// Picture size, finally a simple one :-)
sps->pic_width_in_mbs_minus1 = ((input->img_width+img->auto_crop_right)/16) -1;
sps->pic_height_in_map_units_minus1 = (((input->img_height+img->auto_crop_bottom)/16)/ (2 - sps->frame_mbs_only_flag)) - 1;
// a couple of flags, simple
sps->mb_adaptive_frame_field_flag = (Boolean) (FRAME_CODING != input->MbInterlace);
sps->direct_8x8_inference_flag = (Boolean) input->directInferenceFlag;
// Sequence VUI not implemented, signalled as not present
sps->vui_parameters_present_flag = (Boolean) ((input->rgb_input_flag && input->yuv_format==3)|| input->Generate_SEIVUI);
sps->chroma_format_idc = input->yuv_format;
// This should be moved somewhere else.
{
int PicWidthInMbs, PicHeightInMapUnits, FrameHeightInMbs;
int width, height;
PicWidthInMbs = (sps->pic_width_in_mbs_minus1 +1);
PicHeightInMapUnits = (sps->pic_height_in_map_units_minus1 +1);
FrameHeightInMbs = ( 2 - sps->frame_mbs_only_flag ) * PicHeightInMapUnits;
width = PicWidthInMbs * MB_BLOCK_SIZE;
height = FrameHeightInMbs * MB_BLOCK_SIZE;
Co_located = alloc_colocated (width, height,sps->mb_adaptive_frame_field_flag);
}
// Fidelity Range Extensions stuff
if(frext_profile)
{
sps->seq_scaling_matrix_present_flag = (Boolean) (input->ScalingMatrixPresentFlag&1);
for(i=0; i<8; i++)
{
if(i<6)
sps->seq_scaling_list_present_flag[i] = (input->ScalingListPresentFlag[i]&1);
else
{
if(input->Transform8x8Mode)
sps->seq_scaling_list_present_flag[i] = (input->ScalingListPresentFlag[i]&1);
else
sps->seq_scaling_list_present_flag[i] = 0;
}
}
}
else
{
sps->seq_scaling_matrix_present_flag = FALSE;
for(i=0; i<8; i++)
sps->seq_scaling_list_present_flag[i] = 0;
}
if (img->auto_crop_right || img->auto_crop_bottom)
{
sps->frame_cropping_flag = TRUE;
sps->frame_cropping_rect_left_offset=0;
sps->frame_cropping_rect_top_offset=0;
sps->frame_cropping_rect_right_offset= (img->auto_crop_right / SubWidthC[sps->chroma_format_idc]);
sps->frame_cropping_rect_bottom_offset= (img->auto_crop_bottom / (SubHeightC[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag)));
if (img->auto_crop_right % SubWidthC[sps->chroma_format_idc])
{
error("automatic frame cropping (width) not possible",500);
}
if (img->auto_crop_bottom % (SubHeightC[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag)))
{
error("automatic frame cropping (height) not possible",500);
}
}
else
{
sps->frame_cropping_flag = FALSE;
}
}
/*!
************************************************************************
* \brief
* GeneratePictureParameterSet:
* Generates a Picture Parameter Set structure
*
* \par
* Regarding the QP
* The previous software versions coded the absolute QP only in the
* slice header. This is kept, and the offset in the PPS is coded
* even if we could save bits by intelligently using this field.
*
************************************************************************
*/
void GeneratePictureParameterSet( pic_parameter_set_rbsp_t *pps, //!< Picture Parameter Set to be filled
seq_parameter_set_rbsp_t *sps, //!< used Sequence Parameter Set
int PPS_id, //!< PPS ID
int WeightedPrediction, //!< value of weighted_pred_flag
int WeightedBiprediction, //!< value of weighted_bipred_idc
int cb_qp_index_offset, //!< value of cb_qp_index_offset
int cr_qp_index_offset //!< value of cr_qp_index_offset
)
{
unsigned i;
int frext_profile = ((IdentifyProfile()==FREXT_HP) ||
(IdentifyProfile()==FREXT_Hi10P) ||
(IdentifyProfile()==FREXT_Hi422) ||
(IdentifyProfile()==FREXT_Hi444));
// *************************************************************************
// Picture Parameter Set
// *************************************************************************
pps->seq_parameter_set_id = sps->seq_parameter_set_id;
pps->pic_parameter_set_id = PPS_id;
pps->entropy_coding_mode_flag = (input->symbol_mode==UVLC ? FALSE : TRUE);
// Fidelity Range Extensions stuff
if(frext_profile)
{
pps->transform_8x8_mode_flag = (input->Transform8x8Mode ? TRUE:FALSE);
pps->pic_scaling_matrix_present_flag = (Boolean) ((input->ScalingMatrixPresentFlag&2)>>1);
for(i=0; i<8; i++)
{
if(i<6)
pps->pic_scaling_list_present_flag[i] = (input->ScalingListPresentFlag[i]&2)>>1;
else
{
if(pps->transform_8x8_mode_flag)
pps->pic_scaling_list_present_flag[i] = (input->ScalingListPresentFlag[i]&2)>>1;
else
pps->pic_scaling_list_present_flag[i] = 0;
}
}
}
else
{
pps->pic_scaling_matrix_present_flag = FALSE;
for(i=0; i<8; i++)
pps->pic_scaling_list_present_flag[i] = 0;
pps->transform_8x8_mode_flag = FALSE;
input->Transform8x8Mode = 0;
}
// JVT-Fxxx (by Stephan Wenger, make this flag unconditional
pps->pic_order_present_flag = img->pic_order_present_flag;
// Begin FMO stuff
pps->num_slice_groups_minus1 = input->num_slice_groups_minus1;
//! Following set the parameter for different slice group types
if (pps->num_slice_groups_minus1 > 0)
{
if ((pps->slice_group_id = calloc ((sps->pic_height_in_map_units_minus1+1)*(sps->pic_width_in_mbs_minus1+1), sizeof(byte))) == NULL)
no_mem_exit ("GeneratePictureParameterSet: slice_group_id");
switch (input->slice_group_map_type)
{
case 0:
pps->slice_group_map_type = 0;
for(i=0; i<=pps->num_slice_groups_minus1; i++)
{
pps->run_length_minus1[i]=input->run_length_minus1[i];
}
break;
case 1:
pps->slice_group_map_type = 1;
break;
case 2:
// i loops from 0 to num_slice_groups_minus1-1, because no info for background needed
pps->slice_group_map_type = 2;
for(i=0; i<pps->num_slice_groups_minus1; i++)
{
pps->top_left[i] = input->top_left[i];
pps->bottom_right[i] = input->bottom_right[i];
}
break;
case 3:
case 4:
case 5:
pps->slice_group_map_type = input->slice_group_map_type;
pps->slice_group_change_direction_flag = (Boolean) input->slice_group_change_direction_flag;
pps->slice_group_change_rate_minus1 = input->slice_group_change_rate_minus1;
break;
case 6:
pps->slice_group_map_type = 6;
pps->pic_size_in_map_units_minus1 =
(((input->img_height+img->auto_crop_bottom)/MB_BLOCK_SIZE)/(2-sps->frame_mbs_only_flag))
*((input->img_width+img->auto_crop_right)/MB_BLOCK_SIZE) -1;
for (i=0;i<=pps->pic_size_in_map_units_minus1; i++)
pps->slice_group_id[i] = input->slice_group_id[i];
break;
default:
printf ("Parset.c: slice_group_map_type invalid, default\n");
assert (0==1);
}
}
// End FMO stuff
pps->num_ref_idx_l0_active_minus1 = sps->frame_mbs_only_flag ? (sps->num_ref_frames-1) : (2 * sps->num_ref_frames - 1) ; // set defaults
pps->num_ref_idx_l1_active_minus1 = sps->frame_mbs_only_flag ? (sps->num_ref_frames-1) : (2 * sps->num_ref_frames - 1) ; // set defaults
pps->weighted_pred_flag = (Boolean) WeightedPrediction;
pps->weighted_bipred_idc = WeightedBiprediction;
pps->pic_init_qp_minus26 = 0; // hard coded to zero, QP lives in the slice header
pps->pic_init_qs_minus26 = 0;
pps->chroma_qp_index_offset = cb_qp_index_offset;
if (frext_profile)
{
pps->cb_qp_index_offset = cb_qp_index_offset;
pps->cr_qp_index_offset = cr_qp_index_offset;
}
else
pps->cb_qp_index_offset = pps->cr_qp_index_offset = pps->chroma_qp_index_offset;
pps->deblocking_filter_control_present_flag = (Boolean) input->LFSendParameters;
pps->constrained_intra_pred_flag = (Boolean) input->UseConstrainedIntraPred;
// if redundant slice is in use.
pps->redundant_pic_cnt_present_flag = (Boolean) input->redundant_pic_flag;
}
/*!
*************************************************************************************
* \brief
* syntax for scaling list matrix values
*
* \param scalingListinput
* input scaling list
* \param scalingList
* scaling list to be used
* \param sizeOfScalingList
* size of the scaling list
* \param UseDefaultScalingMatrix
* usage of default Scaling Matrix
* \param bitstream
* target bitstream for writing syntax
*
* \return
* size of the RBSP in bytes
*
*************************************************************************************
*/
int Scaling_List(short *scalingListinput, short *scalingList, int sizeOfScalingList, short *UseDefaultScalingMatrix, Bitstream *bitstream)
{
int j, scanj;
int len=0;
int delta_scale, lastScale, nextScale;
lastScale = 8;
nextScale = 8;
for(j=0; j<sizeOfScalingList; j++)
{
scanj = (sizeOfScalingList==16) ? ZZ_SCAN[j]:ZZ_SCAN8[j];
if(nextScale!=0)
{
delta_scale = scalingListinput[scanj]-lastScale; // Calculate delta from the scalingList data from the input file
if(delta_scale>127)
delta_scale=delta_scale-256;
else if(delta_scale<-128)
delta_scale=delta_scale+256;
len+=se_v (" : delta_sl ", delta_scale, bitstream);
nextScale = scalingListinput[scanj];
*UseDefaultScalingMatrix|=(scanj==0 && nextScale==0); // Check first matrix value for zero
}
scalingList[scanj] = (short) ((nextScale==0) ? lastScale:nextScale); // Update the actual scalingList matrix with the correct values
lastScale = scalingList[scanj];
}
return len;
}
/*!
*************************************************************************************
* \brief
* int GenerateSeq_parameter_set_rbsp (seq_parameter_set_rbsp_t *sps, char *rbsp);
*
* \param sps
* sequence parameter structure
* \param rbsp
* buffer to be filled with the rbsp, size should be at least MAXIMUMPARSETRBSPSIZE
*
* \return
* size of the RBSP in bytes
*
* \note
* Sequence Parameter VUI function is called, but the function implements
* an exit (-1)
*************************************************************************************
*/
int GenerateSeq_parameter_set_rbsp (seq_parameter_set_rbsp_t *sps, byte *rbsp)
{
Bitstream *bitstream;
int len = 0, LenInBytes;
unsigned i;
assert (rbsp != NULL);
if ((bitstream=calloc(1, sizeof(Bitstream)))==NULL) no_mem_exit("SeqParameterSet:bitstream");
// .. and use the rbsp provided (or allocated above) for the data
bitstream->streamBuffer = rbsp;
bitstream->bits_to_go = 8;
len+=u_v (8, "SPS: profile_idc", sps->profile_idc, bitstream);
len+=u_1 ("SPS: constrained_set0_flag", sps->constrained_set0_flag, bitstream);
len+=u_1 ("SPS: constrained_set1_flag", sps->constrained_set1_flag, bitstream);
len+=u_1 ("SPS: constrained_set2_flag", sps->constrained_set2_flag, bitstream);
len+=u_1 ("SPS: constrained_set3_flag", sps->constrained_set3_flag, bitstream);
len+=u_v (4, "SPS: reserved_zero_4bits", 0, bitstream);
len+=u_v (8, "SPS: level_idc", sps->level_idc, bitstream);
len+=ue_v ("SPS: seq_parameter_set_id", sps->seq_parameter_set_id, bitstream);
// Fidelity Range Extensions stuff
if((sps->profile_idc==FREXT_HP) ||
(sps->profile_idc==FREXT_Hi10P) ||
(sps->profile_idc==FREXT_Hi422) ||
(sps->profile_idc==FREXT_Hi444))
{
len+=ue_v ("SPS: chroma_format_idc", sps->chroma_format_idc, bitstream);
if(img->yuv_format == 3)
len+=u_1 ("SPS: residue_transform_flag", 0, bitstream);
len+=ue_v ("SPS: bit_depth_luma_minus8", sps->bit_depth_luma_minus8, bitstream);
len+=ue_v ("SPS: bit_depth_chroma_minus8", sps->bit_depth_chroma_minus8, bitstream);
len+=u_1 ("SPS: lossless_qpprime_y_zero_flag", img->lossless_qpprime_flag, bitstream);
//other chroma info to be added in the future
len+=u_1 ("SPS: seq_scaling_matrix_present_flag", sps->seq_scaling_matrix_present_flag, bitstream);
if(sps->seq_scaling_matrix_present_flag)
{
for(i=0; i<8; i++)
{
len+=u_1 ("SPS: seq_scaling_list_present_flag", sps->seq_scaling_list_present_flag[i], bitstream);
if(sps->seq_scaling_list_present_flag[i])
{
if(i<6)
len+=Scaling_List(ScalingList4x4input[i], ScalingList4x4[i], 16, &UseDefaultScalingMatrix4x4Flag[i], bitstream);
else
len+=Scaling_List(ScalingList8x8input[i-6], ScalingList8x8[i-6], 64, &UseDefaultScalingMatrix8x8Flag[i-6], bitstream);
}
}
}
}
len+=ue_v ("SPS: log2_max_frame_num_minus4", sps->log2_max_frame_num_minus4, bitstream);
len+=ue_v ("SPS: pic_order_cnt_type", sps->pic_order_cnt_type, bitstream);
if (sps->pic_order_cnt_type == 0)
len+=ue_v ("SPS: log2_max_pic_order_cnt_lsb_minus4", sps->log2_max_pic_order_cnt_lsb_minus4, bitstream);
else if (sps->pic_order_cnt_type == 1)
{
len+=u_1 ("SPS: delta_pic_order_always_zero_flag", sps->delta_pic_order_always_zero_flag, bitstream);
len+=se_v ("SPS: offset_for_non_ref_pic", sps->offset_for_non_ref_pic, bitstream);
len+=se_v ("SPS: offset_for_top_to_bottom_field", sps->offset_for_top_to_bottom_field, bitstream);
len+=ue_v ("SPS: num_ref_frames_in_pic_order_cnt_cycle", sps->num_ref_frames_in_pic_order_cnt_cycle, bitstream);
for (i=0; i<sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
len+=se_v ("SPS: offset_for_ref_frame", sps->offset_for_ref_frame[i], bitstream);
}
len+=ue_v ("SPS: num_ref_frames", sps->num_ref_frames, bitstream);
len+=u_1 ("SPS: gaps_in_frame_num_value_allowed_flag", sps->gaps_in_frame_num_value_allowed_flag, bitstream);
len+=ue_v ("SPS: pic_width_in_mbs_minus1", sps->pic_width_in_mbs_minus1, bitstream);
len+=ue_v ("SPS: pic_height_in_map_units_minus1", sps->pic_height_in_map_units_minus1, bitstream);
len+=u_1 ("SPS: frame_mbs_only_flag", sps->frame_mbs_only_flag, bitstream);
if (!sps->frame_mbs_only_flag)
{
len+=u_1 ("SPS: mb_adaptive_frame_field_flag", sps->mb_adaptive_frame_field_flag, bitstream);
}
len+=u_1 ("SPS: direct_8x8_inference_flag", sps->direct_8x8_inference_flag, bitstream);
len+=u_1 ("SPS: frame_cropping_flag", sps->frame_cropping_flag, bitstream);
if (sps->frame_cropping_flag)
{
len+=ue_v ("SPS: frame_cropping_rect_left_offset", sps->frame_cropping_rect_left_offset, bitstream);
len+=ue_v ("SPS: frame_cropping_rect_right_offset", sps->frame_cropping_rect_right_offset, bitstream);
len+=ue_v ("SPS: frame_cropping_rect_top_offset", sps->frame_cropping_rect_top_offset, bitstream);
len+=ue_v ("SPS: frame_cropping_rect_bottom_offset", sps->frame_cropping_rect_bottom_offset, bitstream);
}
len+=u_1 ("SPS: vui_parameters_present_flag", sps->vui_parameters_present_flag, bitstream);
if (sps->vui_parameters_present_flag)
len+=GenerateVUISequenceParameters(bitstream); // currently a dummy, asserting
SODBtoRBSP(bitstream); // copies the last couple of bits into the byte buffer
LenInBytes=bitstream->byte_pos;
free (bitstream);
return LenInBytes;
}
/*!
***********************************************************************************************
* \brief
* int GeneratePic_parameter_set_rbsp (pic_parameter_set_rbsp_t *sps, char *rbsp);
*
* \param pps
* picture parameter structure
* \param rbsp
* buffer to be filled with the rbsp, size should be at least MAXIMUMPARSETRBSPSIZE
*
* \return
* size of the RBSP in bytes, negative in case of an error
*
* \note
* Picture Parameter VUI function is called, but the function implements
* an exit (-1)
************************************************************************************************
*/
int GeneratePic_parameter_set_rbsp (pic_parameter_set_rbsp_t *pps, byte *rbsp)
{
Bitstream *bitstream;
int len = 0, LenInBytes;
unsigned i;
unsigned NumberBitsPerSliceGroupId;
int profile_idc;
assert (rbsp != NULL);
if ((bitstream=calloc(1, sizeof(Bitstream)))==NULL) no_mem_exit("PicParameterSet:bitstream");
// .. and use the rbsp provided (or allocated above) for the data
bitstream->streamBuffer = rbsp;
bitstream->bits_to_go = 8;
pps->pic_order_present_flag = img->pic_order_present_flag;
len+=ue_v ("PPS: pic_parameter_set_id", pps->pic_parameter_set_id, bitstream);
len+=ue_v ("PPS: seq_parameter_set_id", pps->seq_parameter_set_id, bitstream);
len+=u_1 ("PPS: entropy_coding_mode_flag", pps->entropy_coding_mode_flag, bitstream);
len+=u_1 ("PPS: pic_order_present_flag", pps->pic_order_present_flag, bitstream);
len+=ue_v ("PPS: num_slice_groups_minus1", pps->num_slice_groups_minus1, bitstream);
// FMO stuff
if(pps->num_slice_groups_minus1 > 0 )
{
len+=ue_v ("PPS: slice_group_map_type", pps->slice_group_map_type, bitstream);
if (pps->slice_group_map_type == 0)
for (i=0; i<=pps->num_slice_groups_minus1; i++)
len+=ue_v ("PPS: run_length_minus1[i]", pps->run_length_minus1[i], bitstream);
else if (pps->slice_group_map_type==2)
for (i=0; i<pps->num_slice_groups_minus1; i++)
{
len+=ue_v ("PPS: top_left[i]", pps->top_left[i], bitstream);
len+=ue_v ("PPS: bottom_right[i]", pps->bottom_right[i], bitstream);
}
else if (pps->slice_group_map_type == 3 ||
pps->slice_group_map_type == 4 ||
pps->slice_group_map_type == 5)
{
len+=u_1 ("PPS: slice_group_change_direction_flag", pps->slice_group_change_direction_flag, bitstream);
len+=ue_v ("PPS: slice_group_change_rate_minus1", pps->slice_group_change_rate_minus1, bitstream);
}
else if (pps->slice_group_map_type == 6)
{
if (pps->num_slice_groups_minus1>=4)
NumberBitsPerSliceGroupId=3;
else if (pps->num_slice_groups_minus1>=2)
NumberBitsPerSliceGroupId=2;
else if (pps->num_slice_groups_minus1>=1)
NumberBitsPerSliceGroupId=1;
else
NumberBitsPerSliceGroupId=0;
len+=ue_v ("PPS: pic_size_in_map_units_minus1", pps->pic_size_in_map_units_minus1, bitstream);
for(i=0; i<=pps->pic_size_in_map_units_minus1; i++)
len+= u_v (NumberBitsPerSliceGroupId, "PPS: >slice_group_id[i]", pps->slice_group_id[i], bitstream);
}
}
// End of FMO stuff
len+=ue_v ("PPS: num_ref_idx_l0_active_minus1", pps->num_ref_idx_l0_active_minus1, bitstream);
len+=ue_v ("PPS: num_ref_idx_l1_active_minus1", pps->num_ref_idx_l1_active_minus1, bitstream);
len+=u_1 ("PPS: weighted_pred_flag", pps->weighted_pred_flag, bitstream);
len+=u_v (2, "PPS: weighted_bipred_idc", pps->weighted_bipred_idc, bitstream);
len+=se_v ("PPS: pic_init_qp_minus26", pps->pic_init_qp_minus26, bitstream);
len+=se_v ("PPS: pic_init_qs_minus26", pps->pic_init_qs_minus26, bitstream);
profile_idc = IdentifyProfile();
if((profile_idc==FREXT_HP) ||
(profile_idc==FREXT_Hi10P) ||
(profile_idc==FREXT_Hi422) ||
(profile_idc==FREXT_Hi444))
len+=se_v ("PPS: chroma_qp_index_offset", pps->cb_qp_index_offset, bitstream);
else
len+=se_v ("PPS: chroma_qp_index_offset", pps->chroma_qp_index_offset, bitstream);
len+=u_1 ("PPS: deblocking_filter_control_present_flag", pps->deblocking_filter_control_present_flag, bitstream);
len+=u_1 ("PPS: constrained_intra_pred_flag", pps->constrained_intra_pred_flag, bitstream);
len+=u_1 ("PPS: redundant_pic_cnt_present_flag", pps->redundant_pic_cnt_present_flag, bitstream);
// Fidelity Range Extensions stuff
if((profile_idc==FREXT_HP) ||
(profile_idc==FREXT_Hi10P) ||
(profile_idc==FREXT_Hi422) ||
(profile_idc==FREXT_Hi444))
{
len+=u_1 ("PPS: transform_8x8_mode_flag", pps->transform_8x8_mode_flag, bitstream);
len+=u_1 ("PPS: pic_scaling_matrix_present_flag", pps->pic_scaling_matrix_present_flag, bitstream);
if(pps->pic_scaling_matrix_present_flag)
{
for(i=0; i<(6+((unsigned)pps->transform_8x8_mode_flag<<1)); i++)
{
len+=u_1 ("PPS: pic_scaling_list_present_flag", pps->pic_scaling_list_present_flag[i], bitstream);
if(pps->pic_scaling_list_present_flag[i])
{
if(i<6)
len+=Scaling_List(ScalingList4x4input[i], ScalingList4x4[i], 16, &UseDefaultScalingMatrix4x4Flag[i], bitstream);
else
len+=Scaling_List(ScalingList8x8input[i-6], ScalingList8x8[i-6], 64, &UseDefaultScalingMatrix8x8Flag[i-6], bitstream);
}
}
}
len+=se_v ("PPS: second_chroma_qp_index_offset", pps->cr_qp_index_offset, bitstream);
}
SODBtoRBSP(bitstream); // copies the last couple of bits into the byte buffer
LenInBytes=bitstream->byte_pos;
// Get rid of the helper structures
free (bitstream);
return LenInBytes;
}
/*!
*************************************************************************************
* \brief
* Returns the Profile
*
* \return
* Profile according to Annex A
*
* \note
* Function is currently a dummy. Should "calculate" the profile from those
* config file parameters. E.g.
*
* Profile = Baseline;
* if (CABAC Used || Interlace used) Profile=Main;
* if (!Cabac Used) && (Bframes | SPframes) Profile = Streaming;
*
*************************************************************************************
*/
int IdentifyProfile(void)
{
return input->ProfileIDC;
}
/*!
*************************************************************************************
* \brief
* Returns the Level
*
* \return
* Level according to Annex A
*
* \note
* This function is currently a dummy, but should calculate the level out of
* the config file parameters (primarily the picture size)
*************************************************************************************
*/
int IdentifyLevel(void)
{
return input->LevelIDC;
}
/*!
*************************************************************************************
* \brief
* Function body for VUI Parameter generation (to be done)
*
* \return
* exits with error message
*************************************************************************************
*/
static int GenerateVUISequenceParameters(Bitstream *bitstream)
{
int len=0;
// special case to signal the RGB format
if(input->rgb_input_flag && input->yuv_format==3)
{
//still pretty much a dummy VUI
printf ("VUI: writing Sequence Parameter VUI to signal RGB format\n");
len+=u_1 ("VUI: aspect_ratio_info_present_flag", 0, bitstream);
len+=u_1 ("VUI: overscan_info_present_flag", 0, bitstream);
len+=u_1 ("VUI: video_signal_type_present_flag", 1, bitstream);
len+=u_v (3, "VUI: video format", 2, bitstream);
len+=u_1 ("VUI: video_full_range_flag", 1, bitstream);
len+=u_1 ("VUI: color_description_present_flag", 1, bitstream);
len+=u_v (8, "VUI: colour primaries", 2, bitstream);
len+=u_v (8, "VUI: transfer characteristics", 2, bitstream);
len+=u_v (8, "VUI: matrix coefficients", 0, bitstream);
len+=u_1 ("VUI: chroma_loc_info_present_flag", 0, bitstream);
len+=u_1 ("VUI: timing_info_present_flag", 0, bitstream);
len+=u_1 ("VUI: nal_hrd_parameters_present_flag", 0, bitstream);
len+=u_1 ("VUI: vcl_hrd_parameters_present_flag", 0, bitstream);
len+=u_1 ("VUI: pic_struc_present_flag", 0, bitstream);
len+=u_1 ("VUI: bitstream_restriction_flag", 0, bitstream);
return len;
}
else if (input->Generate_SEIVUI)
{
int bitstream_restriction_flag = 0;
int timing_info_present_flag = 0;
int aspect_ratio_info_present_flag = 0;
len+=u_1 ("VUI: aspect_ratio_info_present_flag", 0, bitstream);
if (aspect_ratio_info_present_flag)
{
len+=u_v (8,"VUI: aspect_ratio_idc", 1, bitstream);
}
len+=u_1 ("VUI: overscan_info_present_flag", 0, bitstream);
len+=u_1 ("VUI: video_signal_type_present_flag", 0, bitstream);
len+=u_1 ("VUI: chroma_loc_info_present_flag", 0, bitstream);
len+=u_1 ("VUI: timing_info_present_flag", timing_info_present_flag, bitstream);
// timing parameters
if (timing_info_present_flag)
{
len+=u_v (32,"VUI: num_units_in_tick", 416667, bitstream);
len+=u_v (32,"VUI: time_scale", 20000000, bitstream);
len+=u_1 ("VUI: fixed_frame_rate_flag", 1, bitstream);
}
// end of timing parameters
len+=u_1 ("VUI: nal_hrd_parameters_present_flag", 0, bitstream);
len+=u_1 ("VUI: vcl_hrd_parameters_present_flag", 0, bitstream);
len+=u_1 ("VUI: pic_struc_present_flag", 0, bitstream);
len+=u_1 ("VUI: bitstream_restriction_flag", bitstream_restriction_flag, bitstream);
if (bitstream_restriction_flag)
{
len+=u_1 ("VUI: motion_vectors_over_pic_boundaries_flag", 1, bitstream);
len+=ue_v ("VUI: max_bytes_per_pic_denom", 0, bitstream);
len+=ue_v ("VUI: max_bits_per_mb_denom", 0, bitstream);
len+=ue_v ("VUI: log2_max_mv_length_horizontal", 11, bitstream);
len+=ue_v ("VUI: log2_max_mv_length_vertical", 11, bitstream);
len+=ue_v ("VUI: num_reorder_frames", 3, bitstream);
len+=ue_v ("VUI: max_dec_frame_buffering", 4, bitstream);
}
}
else
{
printf ("Sequence Parameter VUI not yet implemented, this should never happen, exit\n");
exit (-1);
}
return 1;
}
/*!
*************************************************************************************
* \brief
* Function body for SEI message NALU generation
*
* \return
* A NALU containing the SEI messages
*
*************************************************************************************
*/
NALU_t *GenerateSEImessage_NALU()
{
NALU_t *n = AllocNALU(64000);
int RBSPlen = 0;
int NALUlen;
byte rbsp[MAXRBSPSIZE];
RBSPlen = GenerateSEImessage_rbsp (NORMAL_SEI, rbsp);
NALUlen = RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_SEI, NALU_PRIORITY_DISPOSABLE, 0, 1);
n->startcodeprefix_len = 4;
return n;
}
/*!
*************************************************************************************
* \brief
* int GenerateSEImessage_rbsp (int, bufferingperiod_information_struct*, char*)
*
*
* \return
* size of the RBSP in bytes, negative in case of an error
*
* \note
*************************************************************************************
*/
int GenerateSEImessage_rbsp (int id, byte *rbsp)
{
Bitstream *bitstream;
int len = 0, LenInBytes;
assert (rbsp != NULL);
if ((bitstream=calloc(1, sizeof(Bitstream)))==NULL) no_mem_exit("SeqParameterSet:bitstream");
// .. and use the rbsp provided (or allocated above) for the data
bitstream->streamBuffer = rbsp;
bitstream->bits_to_go = 8;
{
char sei_message[500];
char uuid_message[9] = "RandomMSG"; // This is supposed to be Random
unsigned int i, message_size = strlen(input->SEIMessageText);
struct TIMEB tstruct;
ftime( &tstruct); // start time ms
if (message_size == 0)
{
message_size = 13;
strncpy(sei_message,"Empty Message",message_size);
}
else
strncpy(sei_message,input->SEIMessageText,message_size);
len+=u_v (8,"SEI: last_payload_type_byte", 5, bitstream);
message_size += 17;
while (message_size > 254)
{
len+=u_v (8,"SEI: ff_byte",255, bitstream);
message_size -= 255;
}
len+=u_v (8,"SEI: last_payload_size_byte",message_size, bitstream);
// Lets randomize uuid based on time
len+=u_v (32,"SEI: uuid_iso_iec_11578",(int) tstruct.timezone, bitstream);
len+=u_v (32,"SEI: uuid_iso_iec_11578",(int) tstruct.time*1000+tstruct.millitm, bitstream);
len+=u_v (32,"SEI: uuid_iso_iec_11578",(int) (uuid_message[0] << 24) + (uuid_message[1] << 16) + (uuid_message[2] << 8) + (uuid_message[3] << 0), bitstream);
len+=u_v (32,"SEI: uuid_iso_iec_11578",(int) (uuid_message[4] << 24) + (uuid_message[5] << 16) + (uuid_message[6] << 8) + (uuid_message[7] << 0), bitstream);
for (i = 0; i < strlen(sei_message); i++)
len+=u_v (8,"SEI: user_data_payload_byte",sei_message[i], bitstream);
len+=u_v (8,"SEI: user_data_payload_byte", 0, bitstream);
}
SODBtoRBSP(bitstream); // copies the last couple of bits into the byte buffer
LenInBytes=bitstream->byte_pos;
free(bitstream);
return LenInBytes;
}