int main(int argc, char **argv) { FILE *infile, *strfile, *reconfile; uint32_t input_file_size; //TODO: Support file size values larger than 32 bits yuv_frame_t orig,ref[MAX_REF_FRAMES]; yuv_frame_t rec[MAX_REORDER_BUFFER]; int rec_available[MAX_REORDER_BUFFER] = {0}; int last_frame_output=-1; int num_encoded_frames,num_bits,start_bits,end_bits; int sub_gop=1; int rec_buffer_idx; int frame_num,frame_num0,k,r; int frame_offset; int ysize,csize,frame_size; int width,height,input_stride_y,input_stride_c; uint32_t acc_num_bits; snrvals psnr; snrvals accsnr; double bit_rate_in_kbps; enc_params *params; encoder_info_t encoder_info; init_use_simd(); /* Read commands from command line and from configuration file(s) */ if (argc < 3) { fprintf(stdout,"usage: %s <parameters>\n",argv[0]); fatalerror(""); } params = parse_config_params(argc, argv); if (params == NULL) { fatalerror("Error while reading encoder paramaters."); } check_parameters(params); /* Open files */ if (!(infile = fopen(params->infilestr,"rb"))) { fatalerror("Could not open in-file for reading."); } if (!(strfile = fopen(params->outfilestr,"wb"))) { fatalerror("Could not open out-file for writing."); } reconfile = NULL; if (params->reconfilestr && !(reconfile = fopen(params->reconfilestr,"wb"))) { fatalerror("Could not open recon-file for reading."); } fseek(infile, 0, SEEK_END); input_file_size = ftell(infile); fseek(infile, 0, SEEK_SET); accsnr.y = 0; accsnr.u = 0; accsnr.v = 0; acc_num_bits = 0; height = params->height; width = params->width; input_stride_y = width; input_stride_c = width/2; ysize = height * width; csize = ysize / 4; frame_size = ysize + 2*csize; /* Create frames*/ create_yuv_frame(&orig,width,height,0,0,0,0); for (r=0;r<MAX_REORDER_BUFFER;r++){ create_yuv_frame(&rec[r],width,height,0,0,0,0); } for (r=0;r<MAX_REF_FRAMES;r++){ //TODO: Use Long-term frame instead of a large sliding window create_yuv_frame(&ref[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2); } /* Initialize main bit stream */ stream_t stream; stream.bitstream = (uint8_t *)malloc(MAX_BUFFER_SIZE * sizeof(uint8_t)); stream.bitbuf = 0; stream.bitrest = 32; stream.bytepos = 0; stream.bytesize = MAX_BUFFER_SIZE; /* Configure encoder */ encoder_info.params = params; encoder_info.orig = &orig; for (r=0;r<MAX_REF_FRAMES;r++){ encoder_info.ref[r] = &ref[r]; } encoder_info.stream = &stream; encoder_info.width = width; encoder_info.height = height; encoder_info.deblock_data = (deblock_data_t *)malloc((height/MIN_PB_SIZE) * (width/MIN_PB_SIZE) * sizeof(deblock_data_t)); /* Write sequence header */ //TODO: Separate function for sequence header start_bits = get_bit_pos(&stream); putbits(16,width,&stream); putbits(16,height,&stream); putbits(1,params->enable_pb_split,&stream); putbits(1,params->enable_tb_split,&stream); putbits(2,params->max_num_ref-1,&stream); //TODO: Support more than 4 reference frames putbits(4,params->num_reorder_pics,&stream);// Max 15 reordered pictures putbits(2,params->max_delta_qp,&stream); putbits(1,params->deblocking,&stream); putbits(1,params->clpf,&stream); putbits(1,params->use_block_contexts,&stream); putbits(1,params->enable_bipred,&stream); end_bits = get_bit_pos(&stream); num_bits = end_bits-start_bits; acc_num_bits += num_bits; printf("SH: %4d bits\n",num_bits); /* Start encoding sequence */ num_encoded_frames = 0; sub_gop = max(1,params->num_reorder_pics+1); for (frame_num0 = params->skip; frame_num0 < (params->skip + params->num_frames) && (frame_num0+sub_gop)*frame_size <= input_file_size; frame_num0+=sub_gop) { for (k=0; k<sub_gop; k++) { int r,r0,r1,r2,r3; /* Initialize frame info */ frame_offset = reorder_frame_offset(k,sub_gop); frame_num = frame_num0 + frame_offset; // If there is an initial I frame and reordering need to jump to the next P frame if (frame_num<params->skip) continue; encoder_info.frame_info.frame_num = frame_num - params->skip; rec_buffer_idx = encoder_info.frame_info.frame_num%MAX_REORDER_BUFFER; encoder_info.rec = &rec[rec_buffer_idx]; encoder_info.rec->frame_num = encoder_info.frame_info.frame_num; if (params->num_reorder_pics==0) { if (params->intra_period > 0) encoder_info.frame_info.frame_type = ((num_encoded_frames%params->intra_period) == 0 ? I_FRAME : P_FRAME); else encoder_info.frame_info.frame_type = (num_encoded_frames == 0 ? I_FRAME : P_FRAME); } else { if (params->intra_period > 0) encoder_info.frame_info.frame_type = ((encoder_info.frame_info.frame_num%params->intra_period) == 0 ? I_FRAME : ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME)); else encoder_info.frame_info.frame_type = (encoder_info.frame_info.frame_num == 0 ? I_FRAME : ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME)); } int coded_phase = (num_encoded_frames + sub_gop - 2) % sub_gop + 1; int b_level = log2i(coded_phase); if (encoder_info.frame_info.frame_type == I_FRAME){ encoder_info.frame_info.qp = params->qp + params->dqpI; } else if (params->num_reorder_pics==0) { if (num_encoded_frames % params->HQperiod) encoder_info.frame_info.qp = (int)(params->mqpP*(float)params->qp) + params->dqpP; else encoder_info.frame_info.qp = params->qp; } else { if (encoder_info.frame_info.frame_num % sub_gop){ float mqpB = params->mqpB; #if DYADIC_CODING mqpB = 1.0+(b_level+1)*((mqpB-1.0)/2.0); #endif encoder_info.frame_info.qp = (int)(mqpB*(float)params->qp) + params->dqpB; } else encoder_info.frame_info.qp = params->qp; } encoder_info.frame_info.num_ref = min(num_encoded_frames,params->max_num_ref); if (params->num_reorder_pics > 0) { #if DYADIC_CODING /* if we have a P frame then use the previous P frame as a reference */ if ((num_encoded_frames-1) % sub_gop == 0) { if (num_encoded_frames==1) encoder_info.frame_info.ref_array[0] = 0; else encoder_info.frame_info.ref_array[0] = sub_gop-1; if (encoder_info.frame_info.num_ref>1 ) encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1)); for (r=2;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-1; } } else { int display_phase = (encoder_info.frame_info.frame_num-1) % sub_gop; int ref_offset=sub_gop>>(b_level+1); encoder_info.frame_info.ref_array[0]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase-ref_offset+1]-1); encoder_info.frame_info.ref_array[1]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase+ref_offset+1]-1); /* use most recent frames for the last ref(s)*/ for (r=2;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-2; } } #else /* if we have a P frame then use the previous P frame as a reference */ if ((num_encoded_frames-1) % sub_gop == 0) { if (num_encoded_frames==1) encoder_info.frame_info.ref_array[0] = 0; else encoder_info.frame_info.ref_array[0] = sub_gop-1; if (encoder_info.frame_info.num_ref>1 ) encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1)); for (r=2;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-1; } } else { // Use the last encoded frame as the first ref if (encoder_info.frame_info.num_ref>0) { encoder_info.frame_info.ref_array[0] = 0; } /* Use the subsequent P frame as the 2nd ref */ int phase = (num_encoded_frames + sub_gop - 2) % sub_gop; if (encoder_info.frame_info.num_ref>1) { if (phase==0) encoder_info.frame_info.ref_array[1] = min(sub_gop, num_encoded_frames-1); else encoder_info.frame_info.ref_array[1] = min(phase, num_encoded_frames-1); } /* Use the prior P frame as the 3rd ref */ if (encoder_info.frame_info.num_ref>2) { encoder_info.frame_info.ref_array[2] = min(phase ? phase + sub_gop : 2*sub_gop, num_encoded_frames-1); } /* use most recent frames for the last ref(s)*/ for (r=3;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-3+1; } } #endif } else { if (encoder_info.frame_info.num_ref==1){ /* If num_ref==1 always use most recent frame */ encoder_info.frame_info.ref_array[0] = 0; } else if (encoder_info.frame_info.num_ref==2){ /* If num_ref==2 use most recent LQ frame and most recent HQ frame */ r0 = 0; r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1; encoder_info.frame_info.ref_array[0] = r0; encoder_info.frame_info.ref_array[1] = r1; } else if (encoder_info.frame_info.num_ref==3){ r0 = 0; r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1; r2 = r1==1 ? 2 : 1; encoder_info.frame_info.ref_array[0] = r0; encoder_info.frame_info.ref_array[1] = r1; encoder_info.frame_info.ref_array[2] = r2; } else if (encoder_info.frame_info.num_ref==4){ r0 = 0; r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1; r2 = r1==1 ? 2 : 1; r3 = r2+1; if (r3==r1) r3 += 1; encoder_info.frame_info.ref_array[0] = r0; encoder_info.frame_info.ref_array[1] = r1; encoder_info.frame_info.ref_array[2] = r2; encoder_info.frame_info.ref_array[3] = r3; } else{ for (r=0;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r; } } } if (params->intra_rdo){ if (encoder_info.frame_info.frame_type == I_FRAME){ encoder_info.frame_info.num_intra_modes = 10; } else{ encoder_info.frame_info.num_intra_modes = params->encoder_speed > 0 ? 4 : 10; } } else{ encoder_info.frame_info.num_intra_modes = 4; } #if 0 /* To test sliding window operation */ int offsetx = 500; int offsety = 200; int offset_rec = encoder_info.rec->offset_y + offsety * encoder_info.rec->stride_y + offsetx; int offset_ref = encoder_info.ref[0]->offset_y + offsety * encoder_info.ref[0]->stride_y + offsetx; if (encoder_info.frame_info.num_ref==2){ int r0 = encoder_info.frame_info.ref_array[0]; int r1 = encoder_info.frame_info.ref_array[1]; printf("ref0=%3d ref1=%3d ",encoder_info.ref[r0]->y[offset_ref],encoder_info.ref[r1]->y[offset_ref]); } else{ printf("ref0=XXX ref1=XXX "); } #endif /* Read input frame */ fseek(infile, frame_num*(frame_size+params->frame_headerlen)+params->file_headerlen+params->frame_headerlen, SEEK_SET); read_yuv_frame(&orig,width,height,infile); orig.frame_num = encoder_info.frame_info.frame_num; /* Encode frame */ start_bits = get_bit_pos(&stream); encode_frame(&encoder_info); rec_available[rec_buffer_idx]=1; end_bits = get_bit_pos(&stream); num_bits = end_bits-start_bits; num_encoded_frames++; /* Compute SNR */ if (params->snrcalc){ snr_yuv(&psnr,&orig,&rec[rec_buffer_idx],height,width,input_stride_y,input_stride_c); } else{ psnr.y = psnr.u = psnr.v = 0.0; } accsnr.y += psnr.y; accsnr.u += psnr.u; accsnr.v += psnr.v; acc_num_bits += num_bits; if (encoder_info.frame_info.frame_type==I_FRAME) fprintf(stdout,"%4d I %4d %10d %10.4f %8.4f %8.4f ",frame_num,encoder_info.frame_info.qp,num_bits,psnr.y,psnr.u,psnr.v); else if (encoder_info.frame_info.frame_type==P_FRAME) fprintf(stdout,"%4d P %4d %10d %10.4f %8.4f %8.4f ",frame_num,encoder_info.frame_info.qp,num_bits,psnr.y,psnr.u,psnr.v); else fprintf(stdout,"%4d B %4d %10d %10.4f %8.4f %8.4f ",frame_num,encoder_info.frame_info.qp,num_bits,psnr.y,psnr.u,psnr.v); for (r=0;r<encoder_info.frame_info.num_ref;r++){ fprintf(stdout,"%3d",encoder_info.frame_info.ref_array[r]); } fprintf(stdout,"\n"); fflush(stdout); /* Write compressed bits for this frame to file */ flush_bytebuf(&stream, strfile); if (reconfile){ /* Write output frame */ rec_buffer_idx = (last_frame_output+1) % MAX_REORDER_BUFFER; if (rec_available[rec_buffer_idx]) { last_frame_output++; write_yuv_frame(&rec[rec_buffer_idx],width,height,reconfile); rec_available[rec_buffer_idx]=0; } } } }
int main(int argc, char** argv) { FILE *infile,*outfile; decoder_info_t decoder_info; stream_t stream; yuv_frame_t rec[MAX_REORDER_BUFFER]; yuv_frame_t ref[MAX_REF_FRAMES]; int rec_available[MAX_REORDER_BUFFER]={0}; int rec_buffer_idx; int op_rec_buffer_idx; int decode_frame_num = 0; int last_frame_output = -1; int done = 0; int width; int height; int r; init_use_simd(); parse_arg(argc, argv, &infile, &outfile); fseek(infile, 0, SEEK_END); int input_file_size = ftell(infile); fseek(infile, 0, SEEK_SET); initbits_dec(infile, &stream); decoder_info.stream = &stream; memset(&decoder_info.bit_count,0,sizeof(bit_count_t)); int bit_start = stream.bitcnt; /* Read sequence header */ width = getbits(&stream,16); height = getbits(&stream,16); decoder_info.width = width; decoder_info.height = height; printf("width=%4d height=%4d\n",width,height); decoder_info.pb_split = getbits(&stream,1); printf("pb_split_enable=%1d\n",decoder_info.pb_split); //TODO: Rename variable to pb_split_enable decoder_info.tb_split_enable = getbits(&stream,1); printf("tb_split_enable=%1d\n",decoder_info.tb_split_enable); decoder_info.max_num_ref = getbits(&stream,2) + 1; fprintf(stderr,"num refs is %d\n",decoder_info.max_num_ref); decoder_info.interp_ref = getbits(&stream,1); decoder_info.max_delta_qp = getbits(&stream, 1); decoder_info.deblocking = getbits(&stream,1); decoder_info.clpf = getbits(&stream,1); decoder_info.use_block_contexts = getbits(&stream,1); decoder_info.bipred = getbits(&stream,1); decoder_info.bit_count.sequence_header += (stream.bitcnt - bit_start); for (r=0;r<MAX_REORDER_BUFFER;r++){ create_yuv_frame(&rec[r],width,height,0,0,0,0); } for (r=0;r<MAX_REF_FRAMES;r++){ create_yuv_frame(&ref[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2); decoder_info.ref[r] = &ref[r]; } if (decoder_info.interp_ref) { for (r=0;r<MAX_SKIP_FRAMES;r++){ decoder_info.interp_frames[r] = malloc(sizeof(yuv_frame_t)); create_yuv_frame(decoder_info.interp_frames[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2); } } decoder_info.deblock_data = (deblock_data_t *)malloc((height/MIN_PB_SIZE) * (width/MIN_PB_SIZE) * sizeof(deblock_data_t)); do { decoder_info.frame_info.decode_order_frame_num = decode_frame_num; decode_frame(&decoder_info,rec); rec_buffer_idx = decoder_info.frame_info.display_frame_num%MAX_REORDER_BUFFER; rec_available[rec_buffer_idx]=1; done = initbits_dec(infile, &stream); op_rec_buffer_idx = (last_frame_output+1)%MAX_REORDER_BUFFER; if (rec_available[op_rec_buffer_idx]) { last_frame_output++; write_yuv_frame(&rec[op_rec_buffer_idx],width,height,outfile); rec_available[op_rec_buffer_idx] = 0; } printf("decode_frame_num=%4d display_frame_num=%4d input_file_size=%12d bitcnt=%12d\n", decode_frame_num,decoder_info.frame_info.display_frame_num,input_file_size,stream.bitcnt); decode_frame_num++; } while (!done); // Output the tail int i,j; for (i=1; i<=MAX_REORDER_BUFFER; ++i) { op_rec_buffer_idx=(last_frame_output+i) % MAX_REORDER_BUFFER; if (rec_available[op_rec_buffer_idx]) write_yuv_frame(&rec[op_rec_buffer_idx],width,height,outfile); else break; } bit_count_t bit_count = decoder_info.bit_count; uint32_t tot_bits[NUM_FRAME_TYPES] = {0}; for (i=0;i<NUM_FRAME_TYPES;i++){ tot_bits[i] = bit_count.frame_header[i] + bit_count.super_mode[i] + bit_count.intra_mode[i] + bit_count.mv[i] + bit_count.skip_idx[i] + bit_count.coeff_y[i] + bit_count.coeff_u[i] + bit_count.coeff_v[i] + bit_count.cbp[i] + bit_count.clpf[i]; } tot_bits[0] += bit_count.sequence_header; int ni = bit_count.frame_type[0]; int np = bit_count.frame_type[1]; int nb = bit_count.frame_type[2]; if (np==0) np = (1<<30); //Hack to avoid division by zero if there are no P frames if (nb==0) nb = (1<<30); //Hack to avoid division by zero if there are no B frames printf("\n\nBIT STATISTICS:\n"); printf("Sequence header: %4d\n",bit_count.sequence_header); printf(" I pictures: P pictures: B pictures:\n"); printf(" total average total average total average\n"); printf("Frame header: %9d %9d %9d %9d %9d %9d\n",bit_count.frame_header[0],bit_count.frame_header[0]/ni,bit_count.frame_header[1],bit_count.frame_header[1]/np,bit_count.frame_header[2],bit_count.frame_header[2]/nb); printf("Super mode: %9d %9d %9d %9d %9d %9d\n",bit_count.super_mode[0],bit_count.super_mode[0]/ni,bit_count.super_mode[1],bit_count.super_mode[1]/np,bit_count.super_mode[2],bit_count.super_mode[2]/nb); printf("Intra mode: %9d %9d %9d %9d %9d %9d\n",bit_count.intra_mode[0],bit_count.intra_mode[0]/ni,bit_count.intra_mode[1],bit_count.intra_mode[1]/np, bit_count.intra_mode[2],bit_count.intra_mode[2]/nb); printf("MV: %9d %9d %9d %9d %9d %9d\n",bit_count.mv[0],bit_count.mv[0],bit_count.mv[1],bit_count.mv[1]/np, bit_count.mv[2],bit_count.mv[2]/nb); printf("Skip idx: %9d %9d %9d %9d %9d %9d\n",bit_count.skip_idx[0],bit_count.skip_idx[0],bit_count.skip_idx[1],bit_count.skip_idx[1]/np,bit_count.skip_idx[2],bit_count.skip_idx[2]/nb); printf("Coeff_y: %9d %9d %9d %9d %9d %9d\n",bit_count.coeff_y[0],bit_count.coeff_y[0]/ni,bit_count.coeff_y[1],bit_count.coeff_y[1]/np,bit_count.coeff_y[2],bit_count.coeff_y[2]/nb); printf("Coeff_u: %9d %9d %9d %9d %9d %9d\n",bit_count.coeff_u[0],bit_count.coeff_u[0]/ni,bit_count.coeff_u[1],bit_count.coeff_u[1]/np,bit_count.coeff_u[2],bit_count.coeff_u[2]/nb); printf("Coeff_v: %9d %9d %9d %9d %9d %9d\n",bit_count.coeff_v[0],bit_count.coeff_v[0]/ni,bit_count.coeff_v[1],bit_count.coeff_v[1]/np,bit_count.coeff_v[2],bit_count.coeff_v[2]/nb); printf("CBP (TU-split): %9d %9d %9d %9d %9d %9d\n",bit_count.cbp[0],bit_count.cbp[0]/ni,bit_count.cbp[1],bit_count.cbp[1]/np,bit_count.cbp[2],bit_count.cbp[2]/nb); printf("CLPF: %9d %9d %9d %9d %9d %9d\n",bit_count.clpf[0],bit_count.clpf[0]/ni,bit_count.clpf[1],bit_count.clpf[1]/np,bit_count.clpf[2],bit_count.clpf[2]/nb); printf("Total: %9d %9d %9d %9d %9d %9d\n",tot_bits[0],tot_bits[0],tot_bits[1],tot_bits[1]/np,tot_bits[2],tot_bits[2]/nb); printf("---------------------------------------------------------------------------------------\n\n"); printf("PARAMETER STATISTICS:\n"); printf(" I pictures: P pictures: B pictures:\n"); printf(" total average total average total average\n"); printf("Skip-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.mode[0][0],bit_count.mode[0][0]/ni,bit_count.mode[1][0],bit_count.mode[1][0]/np,bit_count.mode[2][0],bit_count.mode[2][0]/nb); printf("Intra-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.mode[0][1],bit_count.mode[0][1]/ni,bit_count.mode[1][1],bit_count.mode[1][1]/np,bit_count.mode[2][1],bit_count.mode[2][1]/nb); printf("Inter-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.mode[0][2],bit_count.mode[0][2]/ni,bit_count.mode[1][2],bit_count.mode[1][2]/np,bit_count.mode[2][2],bit_count.mode[2][2]/nb); printf("Bipred-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.mode[0][3],bit_count.mode[0][3]/ni,bit_count.mode[1][3],bit_count.mode[1][3]/np,bit_count.mode[2][3],bit_count.mode[2][3]/nb); printf("Merge-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.mode[0][4],bit_count.mode[0][4]/ni,bit_count.mode[1][4],bit_count.mode[1][4]/np,bit_count.mode[2][4],bit_count.mode[2][4]/nb); printf("\n"); printf("8x8-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.size[0][0],bit_count.size[0][0]/ni,bit_count.size[1][0],bit_count.size[1][0]/np,bit_count.size[2][0],bit_count.size[2][0]/nb); printf("16x16-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.size[0][1],bit_count.size[0][1]/ni,bit_count.size[1][1],bit_count.size[1][1]/np,bit_count.size[2][1],bit_count.size[2][1]/nb); printf("32x32-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.size[0][2],bit_count.size[0][2]/ni,bit_count.size[1][2],bit_count.size[1][2]/np,bit_count.size[2][2],bit_count.size[2][2]/nb); printf("64x64-blocks (8x8): %9d %9d %9d %9d %9d %9d\n",bit_count.size[0][3],bit_count.size[0][3]/ni,bit_count.size[1][3],bit_count.size[1][3]/np,bit_count.size[2][3],bit_count.size[2][3]/nb); printf("\n"); printf("Mode and size distribution for P pictures:\n"); printf(" SKIP INTRA INTER BIPRED MERGE\n"); printf("8x8-blocks (8x8): %9d %9d %9d %9d %9d\n",bit_count.size_and_mode[P_FRAME][0][0],bit_count.size_and_mode[P_FRAME][0][1],bit_count.size_and_mode[P_FRAME][0][2],bit_count.size_and_mode[P_FRAME][0][3],bit_count.size_and_mode[P_FRAME][0][4]); printf("16x16-blocks (8x8): %9d %9d %9d %9d %9d\n",bit_count.size_and_mode[P_FRAME][1][0],bit_count.size_and_mode[P_FRAME][1][1],bit_count.size_and_mode[P_FRAME][1][2],bit_count.size_and_mode[P_FRAME][1][3],bit_count.size_and_mode[P_FRAME][1][4]); printf("32x32-blocks (8x8): %9d %9d %9d %9d %9d\n",bit_count.size_and_mode[P_FRAME][2][0],bit_count.size_and_mode[P_FRAME][2][1],bit_count.size_and_mode[P_FRAME][2][2],bit_count.size_and_mode[P_FRAME][2][3],bit_count.size_and_mode[P_FRAME][2][4]); printf("64x64-blocks (8x8): %9d %9d %9d %9d %9d\n",bit_count.size_and_mode[P_FRAME][3][0],bit_count.size_and_mode[P_FRAME][3][1],bit_count.size_and_mode[P_FRAME][3][2],bit_count.size_and_mode[P_FRAME][3][3],bit_count.size_and_mode[P_FRAME][3][4]); printf("\n"); printf("Mode and size distribution for B pictures:\n"); printf(" SKIP INTRA INTER BIPRED MERGE\n"); printf("8x8-blocks (8x8): %9d %9d %9d %9d %9d\n", bit_count.size_and_mode[B_FRAME][0][0], bit_count.size_and_mode[B_FRAME][0][1], bit_count.size_and_mode[B_FRAME][0][2], bit_count.size_and_mode[B_FRAME][0][3], bit_count.size_and_mode[B_FRAME][0][4]); printf("16x16-blocks (8x8): %9d %9d %9d %9d %9d\n", bit_count.size_and_mode[B_FRAME][1][0], bit_count.size_and_mode[B_FRAME][1][1], bit_count.size_and_mode[B_FRAME][1][2], bit_count.size_and_mode[B_FRAME][1][3], bit_count.size_and_mode[B_FRAME][1][4]); printf("32x32-blocks (8x8): %9d %9d %9d %9d %9d\n", bit_count.size_and_mode[B_FRAME][2][0], bit_count.size_and_mode[B_FRAME][2][1], bit_count.size_and_mode[B_FRAME][2][2], bit_count.size_and_mode[B_FRAME][2][3], bit_count.size_and_mode[B_FRAME][2][4]); printf("64x64-blocks (8x8): %9d %9d %9d %9d %9d\n", bit_count.size_and_mode[B_FRAME][3][0], bit_count.size_and_mode[B_FRAME][3][1], bit_count.size_and_mode[B_FRAME][3][2], bit_count.size_and_mode[B_FRAME][3][3], bit_count.size_and_mode[B_FRAME][3][4]); int idx; int num = 5 + decoder_info.max_num_ref; printf("\nSuper-mode distribution for P pictures:\n"); printf(" SKIP SPLIT INTERr0 MERGE BIPRED INTRA "); for (i = 1; i < decoder_info.max_num_ref; i++) printf("INTERr%1d ", i); printf("\n"); for (idx=0;idx<NUM_BLOCK_SIZES;idx++){ int size = 8<<idx; printf("%2d x %2d-blocks: ",size,size); for (i=0;i<num;i++){ printf("%8d",bit_count.super_mode_stat[P_FRAME][idx][i]); } printf("\n"); } printf("\nSuper-mode distribution for B pictures:\n"); printf(" SKIP SPLIT INTERr0 MERGE BIPRED INTRA "); for (i = 1; i < decoder_info.max_num_ref; i++) printf("INTERr%1d ", i); printf("\n"); for (idx = 0; idx<NUM_BLOCK_SIZES; idx++) { int size = 8 << idx; printf("%2d x %2d-blocks: ", size, size); for (i = 0; i<num; i++) { printf("%8d", bit_count.super_mode_stat[B_FRAME][idx][i]); } printf("\n"); } int size; int max_num_ref = 4; printf("\n"); printf("Ref_idx and size distribution for P pictures:\n"); for (i=0;i<NUM_BLOCK_SIZES;i++){ size = 1<<(i+3); printf("%2d x %2d-blocks: ",size,size); for (j=0;j<decoder_info.max_num_ref;j++){ printf("%6d",bit_count.size_and_ref_idx[P_FRAME][i][j]); } printf("\n"); } printf("\n"); printf("Ref_idx and size distribution for B pictures:\n"); for (i = 0; i<NUM_BLOCK_SIZES; i++) { size = 1 << (i + 3); printf("%2d x %2d-blocks: ", size, size); for (j = 0; j<decoder_info.max_num_ref; j++) { printf("%6d", bit_count.size_and_ref_idx[B_FRAME][i][j]); } printf("\n"); } printf("\n"); printf("bi-ref-P: "); for (j=0;j<max_num_ref*max_num_ref;j++){ printf("%7d",bit_count.bi_ref[P_FRAME][j]); } printf("\n"); printf("bi-ref-B: "); for (j = 0; j<max_num_ref*max_num_ref; j++) { printf("%7d", bit_count.bi_ref[B_FRAME][j]); } printf("\n"); printf("-----------------------------------------------------------------\n"); for (r=0;r<MAX_REORDER_BUFFER;r++){ close_yuv_frame(&rec[r]); } for (r=0;r<MAX_REF_FRAMES;r++){ close_yuv_frame(&ref[r]); } if (decoder_info.interp_ref) { for (r=0;r<MAX_SKIP_FRAMES;r++){ close_yuv_frame(decoder_info.interp_frames[r]); free(decoder_info.interp_frames[r]); } } free(decoder_info.deblock_data); return 0; }
int main(int argc, char **argv) { FILE *infile, *strfile, *reconfile; uint32_t input_file_size; //TODO: Support file size values larger than 32 bits yuv_frame_t orig,ref[MAX_REF_FRAMES]; yuv_frame_t rec[MAX_REORDER_BUFFER]; int rec_available[MAX_REORDER_BUFFER] = {0}; int last_frame_output=-1; int num_encoded_frames,num_bits,start_bits,end_bits; int sub_gop=1; int rec_buffer_idx; int frame_num,frame_num0,k,r; int frame_offset; int ysize,csize,frame_size; int width,height; int min_interp_depth; int last_intra_frame_num = 0; uint32_t acc_num_bits; snrvals psnr; snrvals accsnr; double bit_rate_in_kbps; enc_params *params; encoder_info_t encoder_info; int y4m_output; // Keep track of last P frame for using the right references for the tail of a sequence in re-ordered modes int last_PorI_frame; init_use_simd(); /* Read commands from command line and from configuration file(s) */ if (argc < 3) { fprintf(stdout,"usage: %s <parameters>\n",argv[0]); fatalerror(""); } params = parse_config_params(argc, argv); if (params == NULL) { fatalerror("Error while reading encoder paramaters."); } check_parameters(params); /* Open files */ if (!(infile = fopen(params->infilestr,"rb"))) { fatalerror("Could not open in-file for reading."); } if (!(strfile = fopen(params->outfilestr,"wb"))) { fatalerror("Could not open out-file for writing."); } reconfile = NULL; y4m_output = 0; if (params->reconfilestr) { char *p; if (!(reconfile = fopen(params->reconfilestr,"wb"))) { fatalerror("Could not open recon-file for reading."); } p = strrchr(params->reconfilestr,'.'); y4m_output = p != NULL && strcmp(p,".y4m") == 0; } fseek(infile, 0, SEEK_END); input_file_size = ftell(infile); fseek(infile, 0, SEEK_SET); if (y4m_output) { fprintf(reconfile, "YUV4MPEG2 W%d H%d F%d:1 Ip A0:0 C420jpeg XYSCSS=420JPEG\x0a", params->width, params->height, (int)params->frame_rate); } accsnr.y = 0; accsnr.u = 0; accsnr.v = 0; acc_num_bits = 0; height = params->height; width = params->width; ysize = height * width; csize = ysize / 4; frame_size = ysize + 2*csize; /* Create frames*/ create_yuv_frame(&orig,width,height,0,0,0,0); for (r=0;r<MAX_REORDER_BUFFER;r++){ create_yuv_frame(&rec[r],width,height,0,0,0,0); } for (r=0;r<MAX_REF_FRAMES;r++){ //TODO: Use Long-term frame instead of a large sliding window create_yuv_frame(&ref[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2); } if (params->interp_ref) { for (r=0;r<MAX_SKIP_FRAMES;r++){ encoder_info.interp_frames[r] = malloc(sizeof(yuv_frame_t)); create_yuv_frame(encoder_info.interp_frames[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2); } } /* Initialize main bit stream */ stream_t stream; stream.bitstream = (uint8_t *)malloc(MAX_BUFFER_SIZE * sizeof(uint8_t)); stream.bitbuf = 0; stream.bitrest = 32; stream.bytepos = 0; stream.bytesize = MAX_BUFFER_SIZE; /* Configure encoder */ encoder_info.params = params; encoder_info.orig = &orig; for (r=0;r<MAX_REF_FRAMES;r++){ encoder_info.ref[r] = &ref[r]; } encoder_info.stream = &stream; encoder_info.width = width; encoder_info.height = height; encoder_info.deblock_data = (deblock_data_t *)malloc((height/MIN_PB_SIZE) * (width/MIN_PB_SIZE) * sizeof(deblock_data_t)); /* Write sequence header */ //TODO: Separate function for sequence header start_bits = get_bit_pos(&stream); putbits(16,width,&stream); putbits(16,height,&stream); putbits(1,params->enable_pb_split,&stream); putbits(1,params->enable_tb_split,&stream); putbits(2,params->max_num_ref-1,&stream); //TODO: Support more than 4 reference frames putbits(1,params->interp_ref,&stream);// Use an interpolated reference frame putbits(1, (params->max_delta_qp || params->bitrate), &stream); putbits(1,params->deblocking,&stream); putbits(1,params->clpf,&stream); putbits(1,params->use_block_contexts,&stream); putbits(1,params->enable_bipred,&stream); end_bits = get_bit_pos(&stream); num_bits = end_bits-start_bits; acc_num_bits += num_bits; printf("SH: %4d bits\n",num_bits); /* Start encoding sequence */ num_encoded_frames = 0; sub_gop = max(1,params->num_reorder_pics+1); min_interp_depth = log2i(params->num_reorder_pics+1)-3; if (params->frame_rate > 30) min_interp_depth--; last_PorI_frame = -1; rate_control_t rc; encoder_info.rc = &rc; if (params->bitrate > 0) { int target_bits = params->bitrate / params->frame_rate; int num_sb = ((width + MAX_BLOCK_SIZE - 1) / MAX_BLOCK_SIZE) * ((height + MAX_BLOCK_SIZE - 1) / MAX_BLOCK_SIZE); init_rate_control_per_sequence(&rc, target_bits, num_sb); } for (frame_num0 = params->skip; frame_num0 < (params->skip + params->num_frames) && (frame_num0+1)*frame_size <= input_file_size; frame_num0+=sub_gop) { for (k=0; k<sub_gop; k++) { int r,r1,r2,r3; /* Initialize frame info */ frame_offset = reorder_frame_offset(k,sub_gop,params->dyadic_coding); frame_num = frame_num0 + frame_offset; // If there is an initial I frame and reordering need to jump to the next P frame if (frame_num<params->skip) continue; encoder_info.frame_info.frame_num = frame_num - params->skip; rec_buffer_idx = encoder_info.frame_info.frame_num%MAX_REORDER_BUFFER; encoder_info.rec = &rec[rec_buffer_idx]; encoder_info.rec->frame_num = encoder_info.frame_info.frame_num; if (params->num_reorder_pics==0) { if (params->intra_period > 0) encoder_info.frame_info.frame_type = ((num_encoded_frames%params->intra_period) == 0 ? I_FRAME : P_FRAME); else encoder_info.frame_info.frame_type = (num_encoded_frames == 0 ? I_FRAME : P_FRAME); } else { if (params->intra_period > 0) encoder_info.frame_info.frame_type = ((encoder_info.frame_info.frame_num%params->intra_period) == 0 ? I_FRAME : ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME)); else encoder_info.frame_info.frame_type = (encoder_info.frame_info.frame_num == 0 ? I_FRAME : ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME)); } int coded_phase = (num_encoded_frames + sub_gop - 2) % sub_gop + 1; int b_level = log2i(coded_phase); encoder_info.frame_info.b_level = b_level; if (encoder_info.frame_info.frame_type == I_FRAME){ encoder_info.frame_info.qp = params->qp + params->dqpI; last_intra_frame_num = encoder_info.frame_info.frame_num; } else if (params->num_reorder_pics==0) { if (num_encoded_frames % params->HQperiod) encoder_info.frame_info.qp = (int)(params->mqpP*(float)params->qp) + params->dqpP; else encoder_info.frame_info.qp = params->qp; } else { if (encoder_info.frame_info.frame_num % sub_gop) { if (params->dyadic_coding){ if (b_level == 0) encoder_info.frame_info.qp = (int)(params->mqpB0*(float)params->qp) + params->dqpB0; else if (b_level == 1) encoder_info.frame_info.qp = (int)(params->mqpB1*(float)params->qp) + params->dqpB1; else if (b_level == 2) encoder_info.frame_info.qp = (int)(params->mqpB2*(float)params->qp) + params->dqpB2; else if (b_level == 3) encoder_info.frame_info.qp = (int)(params->mqpB3*(float)params->qp) + params->dqpB3; else encoder_info.frame_info.qp = (int)(params->mqpB*(float)params->qp) + params->dqpB; } else { encoder_info.frame_info.qp = (int)(params->mqpB*(float)params->qp) + params->dqpB; } } else { if (encoder_info.frame_info.frame_num % params->HQperiod) { encoder_info.frame_info.qp = (int)(params->mqpP*(float)params->qp) + params->dqpP; } else encoder_info.frame_info.qp = params->qp; } } encoder_info.frame_info.qp = clip(encoder_info.frame_info.qp, 0, MAX_QP); encoder_info.frame_info.num_ref = encoder_info.frame_info.frame_type == I_FRAME ? 0 : min(num_encoded_frames,params->max_num_ref); encoder_info.frame_info.interp_ref = 0; if (encoder_info.frame_info.num_ref > 0) { if (params->num_reorder_pics > 0) { if (params->dyadic_coding) { /* if we have a P frame then use the previous P frame as a reference */ if ((num_encoded_frames-1) % sub_gop == 0) { if (num_encoded_frames==1) encoder_info.frame_info.ref_array[0] = 0; else encoder_info.frame_info.ref_array[0] = sub_gop-1; if (encoder_info.frame_info.num_ref>1 ) encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1)); for (r=2;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-2; } } else if (encoder_info.frame_info.num_ref>0){ int display_phase = (encoder_info.frame_info.frame_num-1) % sub_gop; int ref_offset=sub_gop>>(b_level+1); if (b_level >= min_interp_depth && params->interp_ref) { // Need to add another reference if we are at the beginning if (encoder_info.frame_info.num_ref==2) encoder_info.frame_info.num_ref++; encoder_info.frame_info.interp_ref = 1; encoder_info.frame_info.ref_array[1]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase-ref_offset+1]-1); encoder_info.frame_info.ref_array[2]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase+ref_offset+1]-1); // Interpolate these two reference frames to make a new frame encoder_info.frame_info.ref_array[0]=-1; // Add this interpolated frame to the reference buffer and use it as the first reference yuv_frame_t* ref1=encoder_info.ref[encoder_info.frame_info.ref_array[1]]; yuv_frame_t* ref2=encoder_info.ref[encoder_info.frame_info.ref_array[2]]; interpolate_frames(encoder_info.interp_frames[0], ref1, ref2, 2, 1); pad_yuv_frame(encoder_info.interp_frames[0]); encoder_info.interp_frames[0]->frame_num = encoder_info.frame_info.frame_num; /* use most recent frames for the last ref(s)*/ for (r=3;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-3; } } else { encoder_info.frame_info.ref_array[0]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase-ref_offset+1]-1); encoder_info.frame_info.ref_array[1]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase+ref_offset+1]-1); /* use most recent frames for the last ref(s)*/ for (r=2;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-2; } } } } else { /* if we have a P frame then use the previous P frame as a reference */ if ((num_encoded_frames-1) % sub_gop == 0) { if (num_encoded_frames==1) encoder_info.frame_info.ref_array[0] = 0; else encoder_info.frame_info.ref_array[0] = sub_gop-1; if (encoder_info.frame_info.num_ref>1 ) encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1)); for (r=2;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-1; } } else { if (params->interp_ref && encoder_info.frame_info.num_ref>0) { // Need to add another reference if we are at the beginning if (encoder_info.frame_info.num_ref==2) encoder_info.frame_info.num_ref++; encoder_info.frame_info.interp_ref = 1; // Use the last encoded frame as the first true ref if (encoder_info.frame_info.num_ref>0) { encoder_info.frame_info.ref_array[1] = 0; } /* Use the subsequent P frame as the 2nd ref */ int phase = (num_encoded_frames + sub_gop - 2) % sub_gop; if (encoder_info.frame_info.num_ref>1) { if (phase==0) encoder_info.frame_info.ref_array[2] = min(sub_gop, num_encoded_frames-1); else encoder_info.frame_info.ref_array[2] = min(phase, num_encoded_frames-1); } // Interpolate these two reference frames to make a new frame encoder_info.frame_info.ref_array[0]=-1; // Add this interpolated frame to the reference buffer and use it as the first reference yuv_frame_t* ref1=encoder_info.ref[encoder_info.frame_info.ref_array[1]]; yuv_frame_t* ref2=encoder_info.ref[encoder_info.frame_info.ref_array[2]]; interpolate_frames(encoder_info.interp_frames[0], ref1, ref2, sub_gop-phase,phase!=0 ? 1 : sub_gop-phase-1); pad_yuv_frame(encoder_info.interp_frames[0]); encoder_info.interp_frames[0]->frame_num = encoder_info.frame_info.frame_num; /* Use the prior P frame as the 4th ref */ if (encoder_info.frame_info.num_ref>2) { encoder_info.frame_info.ref_array[3] = min(phase ? phase + sub_gop : 2*sub_gop, num_encoded_frames-1); } /* use most recent frames for the last ref(s)*/ for (r=4;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-4+1; } } else { // Use the last encoded frame as the first ref if (encoder_info.frame_info.num_ref>0) { encoder_info.frame_info.ref_array[0] = 0; } /* Use the subsequent P frame as the 2nd ref */ int phase = (num_encoded_frames + sub_gop - 2) % sub_gop; if (encoder_info.frame_info.num_ref>1) { if (phase==0) encoder_info.frame_info.ref_array[1] = min(sub_gop, num_encoded_frames-1); else encoder_info.frame_info.ref_array[1] = min(phase, num_encoded_frames-1); } /* Use the prior P frame as the 3rd ref */ if (encoder_info.frame_info.num_ref>2) { encoder_info.frame_info.ref_array[2] = min(phase ? phase + sub_gop : 2*sub_gop, num_encoded_frames-1); } /* use most recent frames for the last ref(s)*/ for (r=3;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r-3+1; } } } } } else { if (encoder_info.frame_info.num_ref>=1){ /* If num_ref==1 always use most recent frame */ encoder_info.frame_info.ref_array[0] = last_PorI_frame; } if (encoder_info.frame_info.num_ref==2){ /* If num_ref==2 use most recent LQ frame and most recent HQ frame */ r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1; encoder_info.frame_info.ref_array[1] = r1; } else if (encoder_info.frame_info.num_ref==3){ r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1; r2 = r1==1 ? 2 : 1; encoder_info.frame_info.ref_array[1] = r1; encoder_info.frame_info.ref_array[2] = r2; } else if (encoder_info.frame_info.num_ref==4){ r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1; r2 = r1==1 ? 2 : 1; r3 = r2+1; if (r3==r1) r3 += 1; encoder_info.frame_info.ref_array[1] = r1; encoder_info.frame_info.ref_array[2] = r2; encoder_info.frame_info.ref_array[3] = r3; } else{ for (r=1;r<encoder_info.frame_info.num_ref;r++){ encoder_info.frame_info.ref_array[r] = r; } } } }