/************************************************************************ * * main.c, main module of tmn (TMN encoder). * tmn is an H.263+ (H.263 ver. 2.0) encoder somewhat based on the * Test Model Near-term (TMN8) in the ITU-T LBC Experts Group. * * Copyright (C) 1997 University of BC, Canada * * Contacts: * Michael Gallant * Guy Cote * Berna Erol * * UBC Image Processing Laboratory http://www.ee.ubc.ca/image * 2356 Main Mall tel.: +1 604 822 4051 * Vancouver BC Canada V6T1Z4 fax.: +1 604 822 5949 * ************************************************************************/ /* * Disclaimer of Warranty * * These software programs are available to the user without any * license fee or royalty on an "as is" basis. The University of * British Columbia disclaims any and all warranties, whether * express, implied, or statuary, including any implied warranties * or merchantability or of fitness for a particular purpose. In no * event shall the copyright-holder be liable for any incidental, * punitive, or consequential damages of any kind whatsoever arising * from the use of these programs. * * This disclaimer of warranty extends to the user of these programs * and user's customers, employees, agents, transferees, successors, * and assigns. * * The University of British Columbia does not represent or warrant * that the programs furnished hereunder are free of infringement of * any third-party patents. * * Commercial implementations of H.263, including shareware, are * subject to royalty fees to patent holders. Many of these patents * are general enough such that they are unavoidable regardless of * implementation design. * */ #include "h263coder.h" #include "main.h" FILE *streamfile; struct ENCODER_STATE * h263_init_encoder_1() { struct ENCODER_STATE *s; s = malloc(sizeof(struct ENCODER_STATE)); memset(s, 0, sizeof(struct ENCODER_STATE)); s->pic = (Pict *) malloc(sizeof(Pict)); bits = (Bits *) calloc(1, sizeof(Bits)); total_bits = (Bits *) calloc(1, sizeof(Bits)); total_res = (Results *) calloc(1, sizeof(Results)); intra_bits = (Bits *) calloc(1, sizeof(Bits)); intra_res = (Results *) calloc(1, sizeof(Results)); inter_bits = (Bits *) calloc(1, sizeof(Bits)); inter_res = (Results *) calloc(1, sizeof(Results)); scal_bits = (Bits *) calloc(1, sizeof(Bits)); scal_res = (Results *) calloc(1, sizeof(Results)); ei_bits = (Bits *) calloc(1, sizeof(Bits)); ei_res = (Results *) calloc(1, sizeof(Results)); ep_bits = (Bits *) calloc(1, sizeof(Bits)); ep_res = (Results *) calloc(1, sizeof(Results)); res = (Results *) calloc(1, sizeof(Results)); #ifndef FASTIDCT init_idctref(); #endif InitializeCoder(s->pic); return s; } void h263_init_encoder_2(struct ENCODER_STATE *s) { /* rate control variables */ if (targetrate == 0) { rate_control_method = NO; } else { s->pic->bit_rate = targetrate; InitializeRateControl(); } /* pic->src_frame_rate needed to update UFEP */ s->pic->src_frame_rate = (int) (ref_frame_rate / orig_frameskip); s->DelayBetweenFramesInSeconds = (float) 1.0 / (float) s->pic->src_frame_rate; frame_rate = ref_frame_rate / (float) (orig_frameskip * chosen_frameskip); if (rate_control_method == OFFLINE_RC) fprintf(stdout, "Encoding frame rate : %.2f\n", frame_rate); else fprintf(stdout, "Encoding frame rate : variable\n"); fprintf(stdout, "Reference frame rate : %.2f\n", ref_frame_rate); fprintf(stdout, "Orig. seq. frame rate: %.2f\n\n", ref_frame_rate / (float) orig_frameskip); /* check for mode restrictions */ if (syntax_arith_coding && (alternative_inter_vlc || modified_quantization)) { fprintf(stderr, "syntax_arith_coding cannot be used with alternative_inter_vlc or modified_quantization options\n"); exit(-1); } /* Initialize bitcounters */ initbits(); /* Needed for Annex O temporal scalability */ s->fixed_frameskip = chosen_frameskip * orig_frameskip; s->True_B_frameskip = s->fixed_frameskip; /* number of seconds to encode */ seconds = (end - start + chosen_frameskip) * orig_frameskip / ref_frame_rate; if (trace) { strcpy(tracefile, "trace.enc"); /* Open trace-file for writing */ if ((tf = fopen(tracefile, "w")) == NULL) { fprintf(stderr, "Unable to open tracefile\n"); exit(-1); } } if (pb_frames || improved_pb_frames) { pb_bits = (Bits *) calloc(1, sizeof(Bits)); pb_res = (Results *) calloc(1, sizeof(Results)); } if (successive_B_frames) { b_bits = (Bits *) calloc(1, sizeof(Bits)); b_res = (Results *) calloc(1, sizeof(Results)); } if (scalability_mode) { scal_bits = (Bits *) calloc(1, sizeof(Bits)); scal_res = (Results *) calloc(1, sizeof(Results)); } s->pic->UFEP = 0; } int h263_encode_one_frame(struct ENCODER_STATE *s, int i, int tr) { DeterminePictureType(&frame_no, s->pic, s->P_frameskip, s->True_B_frameskip, i); #ifdef VIC s->pic->TR = tr; #endif #ifdef MALLOC_DEBUG_ON fprintf(stderr,"malloc_count: %d\n",malloc_count); #endif if (-1 == s->pic->picture_coding_type) { return -1; } switch (s->pic->picture_coding_type) { case PCT_INTRA: pels = base_pels; lines = base_lines; cpels = base_pels / 2; s->image = ReadImage(seqfilename, frame_no, headerlength); s->curr_image = FillImage(s->image); fprintf(stdout, "Coding I frame... "); s->pic->QUANT = QPI; s->pic->DQUANT = 0; s->curr_recon = CodeOneIntra(s->curr_image, QPI, bits, s->pic); CalculateStatistics(s->curr_image, s->curr_recon, NULL, NULL, bits, QPI, s->pic); /* Special handling if temporal scalability. B frames will be * inserted between the first I-P pair. So the future P frame will * be the next frame coded. It sets prev_P_image and prev_P_recon * based on to the previous next_P_image and next_P_recon, * respectively. */ if (successive_B_frames) { /* Free the past prev_P_image and prev_P_recon, no longer needed */ if (NULL != s->prev_P_image) { FreeImage(s->prev_P_image); FreeImage(s->prev_P_recon); } /* Set new prev_P_image and prev_P_recon to old next_P_image and * next_P_recon respectively */ s->prev_P_image = s->next_P_image; s->prev_P_recon = s->next_P_recon; /* For future I_P pictures, curr_image and curr_recon are set to * prev_image and prev_recon. For B picture prediction, curr_image * and curr_recon represent next_P_image and next_P_recon. */ s->prev_image = s->next_P_image = s->curr_image; s->prev_recon = s->next_P_recon = s->curr_recon; } else { if (NULL != s->prev_image) { FreeImage(s->prev_image); FreeImage(s->prev_recon); } s->prev_image = s->curr_image; s->prev_recon = s->curr_recon; } s->prev_I_P_quant = s->pic->QUANT; /* Frame layer Rate Control */ frameskip = FrameLayerRC(s->pic); fprintf(stdout, "Finished INTRA\n"); break; case PCT_INTER: pframes++; frames++; pels = base_pels; lines = base_lines; cpels = base_pels / 2; if (rate_control_method == OFFLINE_RC) { s->stored_image = s->curr_image; } else { s->image = ReadImage(seqfilename, frame_no, headerlength); s->curr_image = FillImage(s->image); } fprintf(stdout, "Coding P frame %d... ", frame_no); fflush(stdout); /* Set QP to pic->QUANT from previous encoded picture */ QP = s->prev_I_P_quant; s->pic->DQUANT = 0; s->curr_recon = InitImage(pels * lines); CodeOneOrTwo(s->curr_image, NULL, s->prev_image, s->prev_recon, QP, s->P_frameskip * orig_frameskip, bits, s->pic, NULL, s->curr_recon); CalculateStatistics(s->curr_image, s->curr_recon, NULL, NULL, bits, QP, s->pic); /* Specal handling for case of temporal scalability. The P frame being coded * is the future P frame. */ if (successive_B_frames) { /* Free the past prev_P_image and prev_P_recon, no longer needed */ if (NULL != s->prev_P_image) { FreeImage(s->prev_P_image); FreeImage(s->prev_P_recon); } /* Set new prev_P_image and prev_P_recon to old next_P_image and * next_P_recon respectively */ s->prev_P_image = s->next_P_image; s->prev_P_recon = s->next_P_recon; /* For future I_P pictures, curr_image and curr_recon are set to * prev_image and prev_recon. For B picture prediction, curr_image * and curr_recon represent next_P_image and next_P_recon. */ s->prev_image = s->next_P_image = s->curr_image; s->prev_recon = s->next_P_recon = s->curr_recon; } else { if (NULL != s->prev_recon) { FreeImage(s->prev_recon); if ((!scalability_mode) || (scalability_mode && (s->prev_image != s->prev_enhancement_image))) { FreeImage(s->prev_image); } } s->prev_image = s->curr_image; s->prev_recon = s->curr_recon; } /* Frame Layer Rate Control */ frameskip = FrameLayerRC(s->pic); s->prev_I_P_quant = s->pic->QUANT; break; case PCT_PB: case PCT_IPB: bframes++; pframes++; frames += 2; pels = base_pels; lines = base_lines; cpels = base_pels / 2; /* Set QP to pic->QUANT from previous encoded picture */ QP = s->prev_I_P_quant; s->pic->DQUANT = 0; s->image = ReadImage(seqfilename, frame_no, headerlength); s->curr_image = FillImage(s->image); s->B_image = s->curr_image; s->image = ReadImage(seqfilename, frame_no + s->P_frameskip, headerlength); s->curr_image = FillImage(s->image); s->pic->TRB = s->P_frameskip * orig_frameskip; frame_no += s->P_frameskip; /* Code two frames as a PB-frame */ s->B_recon = InitImage(pels * lines); fprintf(stdout, "Coding PB frames %d and %d... ", frame_no - s->P_frameskip, frame_no); fflush(stdout); s->curr_recon = InitImage(pels * lines); /* Code PP or PB pictures. */ CodeOneOrTwo(s->curr_image, s->B_image, s->prev_image, s->prev_recon, QP, 2 * s->P_frameskip * orig_frameskip, bits, s->pic, s->B_recon, s->curr_recon); s->prev_image = s->curr_image; s->prev_recon = s->curr_recon; CalculateStatistics(s->curr_image, s->curr_recon, s->B_image, s->B_recon, bits, s->pic->BQUANT, s->pic); /* Frame Layer Rate Control */ frameskip = FrameLayerRC(s->pic); s->prev_I_P_quant = s->pic->QUANT; break; case PCT_B: Bframes++; frames++; pels = base_pels; lines = base_lines; cpels = base_pels / 2; s->image = ReadImage(seqfilename, frame_no, headerlength); s->curr_image = FillImage(s->image); fprintf(stdout, "Coding B frame... ", frame_no); fflush(stdout); /* Set QP to b_picture_quant, no rate control for true B yet */ QP = b_picture_quant; s->pic->DQUANT = 0; /* Code the next frame as true-B. */ s->curr_recon = InitImage(pels * lines); mv_outside_frame_old = mv_outside_frame; mv_outside_frame = ON; /* Code the current B picture. */ CodeOneTrueB(s->next_P_image, s->curr_image, s->prev_P_image, s->prev_P_recon, QP, s->True_B_frameskip * orig_frameskip, bits, s->pic, s->curr_recon, s->next_P_recon); CalculateStatistics(s->curr_image, s->curr_recon, NULL, NULL, bits, QP, s->pic); mv_outside_frame = mv_outside_frame_old; break; case PCT_EI: EIframes++; pels = enhancement_pels; lines = enhancement_lines; cpels = enhancement_pels / 2; fprintf(stdout, "Coding EI frame %d... ", frame_no); fflush(stdout); /* QP fixed for enhancement layer */ QP = enhancement_layer_quant; s->pic->DQUANT = 0; s->pic->UFEP = 1; s->pic->RLNUM = BASE_LAYER_NUM; s->pic->ELNUM = ENHANCEMENT_LAYER_NUM; /* For all possible spatial scalings */ if (scalability_mode >= 3) { /* No MVs from reference layer, so don't need to frame recon */ s->curr_reference_recon = UpsampleReferenceLayerPicture(s->prev_recon); /* Enhancement layer image is temporally simultaneous, same image as was * just coded in reference layer, i.e. stored as prev_image */ if (enhance_seqfilename[0] == '\0') { s->curr_image = UpsampleReferenceLayerPicture(s->prev_image); } else { s->image = ReadImage(enhance_seqfilename, frame_no, headerlength); s->curr_image = FillImage(s->image); } source_format_old = s->pic->source_format; s->pic->source_format = (scalability_mode >= 7) ? source_format_old + 1 : SF_CUSTOM; } else { s->curr_reference_recon = s->prev_recon; s->curr_image = s->prev_image; } mv_outside_frame_old = mv_outside_frame; mv_outside_frame = ON; s->curr_enhancement_recon = InitImage(pels * lines); CodeOneEI(s->curr_image, s->curr_reference_recon, QP, bits, s->pic, s->curr_enhancement_recon); /* Must apply DF here, as only now do we have fully reconstructed, enhanced picture */ if (deblocking_filter) { EdgeFilter(s->curr_enhancement_recon, s->pic); } CalculateStatistics(s->curr_image, s->curr_enhancement_recon, NULL, NULL, bits, QP, s->pic); mv_outside_frame = mv_outside_frame_old; /* Free the past prev_enhancement_image and prev_enhancement_recon, * no longer needed */ if (NULL != s->prev_enhancement_image) { FreeImage(s->prev_enhancement_image); FreeImage(s->prev_enhancement_recon); } /* Set new prev_enhancement_image and prev_enhancement_recon to old * next_P_image and next_P_recon respectively */ s->prev_enhancement_image = s->curr_image; s->prev_enhancement_recon = s->curr_enhancement_recon; if (scalability_mode >= 3) { s->pic->source_format = source_format_old; } break; case PCT_EP: EPframes++; pels = enhancement_pels; lines = enhancement_lines; cpels = enhancement_pels / 2; fprintf(stdout, "Coding EP frame %d... ", frame_no); fflush(stdout); /* QP fixed for enhancement layer */ QP = enhancement_layer_quant; s->pic->DQUANT = 0; s->pic->UFEP = 1; s->pic->RLNUM = BASE_LAYER_NUM; s->pic->ELNUM = ENHANCEMENT_LAYER_NUM; /* For all possible spatial scalings */ if (scalability_mode >= 3) { /* No MVs from reference layer, so don't need to frame recon */ s->curr_reference_recon = UpsampleReferenceLayerPicture(s->prev_recon); /* Enhancement layer image is temporally simultaneous, same image as was * just coded in reference layer, i.e. stored as prev_image */ if (enhance_seqfilename[0] == '\0') { s->curr_image = UpsampleReferenceLayerPicture(s->prev_image); } else { s->image = ReadImage(enhance_seqfilename, frame_no, headerlength); s->curr_image = FillImage(s->image); } source_format_old = s->pic->source_format; s->pic->source_format = (scalability_mode >= 7) ? source_format_old + 1 : SF_CUSTOM; } else { s->curr_reference_recon = s->prev_recon; s->curr_image = s->prev_image; } s->curr_enhancement_recon = InitImage(pels * lines); mv_outside_frame_old = mv_outside_frame; mv_outside_frame = ON; /* Code the current EI/EP picture. Remember to frame prev_enhancement recon */ CodeOneEP(s->curr_image, s->prev_enhancement_image, s->prev_enhancement_recon, QP, s->P_frameskip * orig_frameskip, bits, s->pic, s->curr_reference_recon, s->curr_enhancement_recon); if (deblocking_filter) { EdgeFilter(s->curr_enhancement_recon, s->pic); } CalculateStatistics(s->curr_image, s->curr_enhancement_recon, NULL, NULL, bits, QP, s->pic); if (NULL != s->prev_enhancement_image) { FreeImage(s->prev_enhancement_image); FreeImage(s->prev_enhancement_recon); } s->prev_enhancement_image = s->curr_image; s->prev_enhancement_recon = s->curr_enhancement_recon; mv_outside_frame = mv_outside_frame_old; if (scalability_mode >= 3) { s->pic->source_format = source_format_old; } break; default: fprintf(stderr,"tmn: oops - default switch\n"); break; } /* Update full extended PTYPE */ if (EPTYPE) { /* UFEP is set once every 5 sec or once every five pictures * * whichever is a larger time interval */ if ((frames % 5 && (s->TR_old - s->TR_new) / s->pic->src_frame_rate >= 5) || (s->TR_old - s->TR_new) / s->pic->src_frame_rate >= 5) { s->TR_new = s->pic->TRB; s->pic->UFEP = ON; } else { s->pic->UFEP = OFF; } s->TR_old = s->pic->TRB; } if (s->pic->PB) { if (write_repeated) wcopies = s->P_frameskip; for (i = 0; i < wcopies; i++) WriteImage(s->B_recon, outputfile); /* write wcopies frames to disk */ } if (write_repeated) { wcopies = (pb_frames ? s->P_frameskip : frameskip); } for (i = 0; i < wcopies; i++) if (PCT_EI == s->pic->picture_coding_type || PCT_EP == s->pic->picture_coding_type) { /* write wcopies frames to disk */ WriteImage(s->curr_enhancement_recon, outputfile_enhance); } else { /* write wcopies frames to disk */ WriteImage(s->curr_recon, outputfile); } /* Can immediately free true B images, as the are never used for prediction */ if (successive_B_frames && PCT_B == s->pic->picture_coding_type) { FreeImage(s->curr_image); FreeImage(s->curr_recon); } s->P_frameskip = (successive_B_frames) ? (successive_B_frames + 1) * s->fixed_frameskip : frameskip; prev_pict_type = s->pic->picture_coding_type; return 0; } void h263_cleanup(struct ENCODER_STATE *s) { #ifndef VIC /* Closing files */ fclose(streamfile); if (trace) { /*fclose(tf);*/ } #endif /* Free memory */ free(streamname); free(seqfilename); free(outputfile); free(tracefile); free(enhance_seqfilename); if (pb_frames || improved_pb_frames) { free(pb_bits); free(pb_res); if (s->pic->PB) { FreeImage(s->B_image); FreeImage(s->B_recon); } } free(s->pic); free(bits); free(res); free(total_bits); free(total_res); free(intra_bits); free(intra_res); free(inter_bits); free(inter_res); if (successive_B_frames) { FreeImage(s->prev_P_image); FreeImage(s->prev_P_recon); FreeImage(s->next_P_image); FreeImage(s->next_P_recon); free(b_bits); free(b_res); } if (scalability_mode) { FreeImage(s->prev_enhancement_image); FreeImage(s->prev_enhancement_recon); free(scal_bits); free(scal_res); } else if (PCT_B != prev_pict_type) { FreeImage(s->curr_image); FreeImage(s->curr_recon); } } #ifndef VIC void main(int argc, char *argv[]) { struct ENCODER_STATE *s; int i; fprintf(stdout, "\nTMN (H.263) coder version 3.0, University of British Columbia, CANADA, based on Telenor's coder version 2.0, Copyright (C) 1995, 1996 Telenor R&D, Norway\n"); s = h263_init_encoder_1(); ProcessArguments(argc, argv, s->pic); h263_init_encoder_2(s); /***** Main loop *****/ for (frame_no = start, i = 0; i <= (end - start) && frame_no <= end; ++i) { if (-1 == h263_encode_one_frame(s,i,0)) break; } /***** end of main loop *****/ /* Print total results */ total_frames_passed = frame_no - start - first_frameskip; fprintf(stdout, "\n==== TOTAL ====\n"); fprintf(stdout, "for %d images of %s\n", frames, seqfilename); if (frames != 0) { if (write_repeated) fprintf(stdout, "Frames saved : %d predicted + %d intra\n", total_frames_passed, icopies); fprintf(stdout, "--------------\n"); if ((pb_frames || improved_pb_frames) && bframes != 0) { fprintf(stdout, "SNR for %d B-frames:\n", bframes); PrintSNR(pb_res, bframes); } if (successive_B_frames && Bframes != 0) { fprintf(stdout, "SNR for %d true B-frames:\n", Bframes); PrintSNR(b_res, Bframes); } if (scalability_mode && EIframes != 0) { fprintf(stdout, "SNR for %d EI frames:\n", EIframes); PrintSNR(ei_res, EIframes); } if (scalability_mode && EPframes != 0) { fprintf(stdout, "SNR for %d EP frames:\n", EPframes); PrintSNR(ep_res, EPframes); } fprintf(stdout, "SNR for %d P-frames:\n", pframes); PrintSNR(inter_res, pframes); if ((pb_frames || improved_pb_frames) && bframes != 0) { fprintf(stdout, "SNR for total %d frames:\n", pframes + bframes); fprintf(stdout, "SNR_Y : %.2f\n", (pb_res->SNR_l + inter_res->SNR_l) / (bframes + pframes)); fprintf(stdout, "SNR_Cb : %.2f\n", (pb_res->SNR_Cb + inter_res->SNR_Cb) / (bframes + pframes)); fprintf(stdout, "SNR_Cr : %.2f\n", (pb_res->SNR_Cr + inter_res->SNR_Cr) / (bframes + pframes)); fprintf(stdout, "--------------\n"); } if (successive_B_frames && Bframes != 0) { fprintf(stdout, "SNR for total %d frames:\n", pframes + Bframes); fprintf(stdout, "SNR_Y : %.2f\n", (b_res->SNR_l + inter_res->SNR_l) / (Bframes + pframes)); fprintf(stdout, "SNR_Cb : %.2f\n", (b_res->SNR_Cb + inter_res->SNR_Cb) / (Bframes + pframes)); fprintf(stdout, "SNR_Cr : %.2f\n", (b_res->SNR_Cr + inter_res->SNR_Cr) / (Bframes + pframes)); fprintf(stdout, "--------------\n"); } if (scalability_mode) { fprintf(stdout, "SNR for total %d enhancement frames:\n", EIframes + EPframes); fprintf(stdout, "SNR_Y : %.2f\n", (ei_res->SNR_l + ep_res->SNR_l) / (EIframes + EPframes)); fprintf(stdout, "SNR_Cb : %.2f\n", (ei_res->SNR_Cb + ep_res->SNR_Cb) / (EIframes + EPframes)); fprintf(stdout, "SNR_Cr : %.2f\n", (ei_res->SNR_Cr + ep_res->SNR_Cr) / (EIframes + EPframes)); fprintf(stdout, "--------------\n"); } fprintf(stdout, "Bit totals for %d(%d) base layer frames:\n", frames, pframes); PrintResult(total_bits, pframes, frames); if (scalability_mode) { fprintf(stdout, "Bit totals for %d(%d) enhancement layer frames:\n", EIframes + EPframes, EPframes); PrintResult(scal_bits, EIframes + EPframes, EIframes + EPframes); } if (targetrate != 0 || s->pic->bit_rate != 0) fprintf(stdout, "Original seq time: %.2f (%.2f) sec\n", (total_frames_passed + first_frameskip) / ref_frame_rate * orig_frameskip, total_frames_passed / ref_frame_rate * orig_frameskip); fprintf(stdout, "Mean quantizer for inter frames : %.2f\n", inter_res->QP_mean / pframes); if (scalability_mode) { fprintf(stdout, "Mean quantizer for enhancement frames : %.2f\n", scal_res->QP_mean / (EIframes + EPframes)); } #if 0 fprintf(stdout, "Total frames : %3d (%3d)\n", total_frames_passed + first_frameskip, total_frames_passed); #endif fprintf(stdout, "Encoded frames : %3d (%3d)\n", frames + 1, frames); if (scalability_mode) { fprintf(stdout, "Encoded frames : %3d (%3d)\n", EIframes + EPframes, EPframes); } mean_frame_rate = frames / (float) total_frames_passed * ref_frame_rate / (float) orig_frameskip; fprintf(stdout, "Mean frame rate : %.2f Hz\n", mean_frame_rate); if (targetrate != 0) fprintf(stdout, "Target bit rate : %.2f kbit/sec\n", targetrate / 1000.0); fprintf(stdout, "Obtained bit rate: %.2f (%.2f) kbit/sec\n", (total_bits->total + intra_bits->total) / ((total_frames_passed + first_frameskip) / ref_frame_rate * orig_frameskip) / 1000.0, (total_bits->total / (float) frames) * mean_frame_rate / 1000.0); if (scalability_mode) { fprintf(stdout, "Obtained enhncement layer bit rate: %.2f kbit/sec\n", (scal_bits->total) / ((total_frames_passed + first_frameskip) / ref_frame_rate * orig_frameskip) / 1000.0); } fprintf(stdout, "============================================\n"); } #if 0 fprintf(stdout, "Total number of bits: %d (%d)\n", total_bits->total + intra_bits->total, (total_bits->total + intra_bits->total) / 8); #endif h263_cleanup(s); exit(0); } #endif /* VIC */ /********************************************************************** * * Name: Help * Description: Prints usage * * ***********************************************************************/ void Help() { fprintf(stdout, "Usage:\tmn [options] -i [more options]\n"); fprintf(stdout, "Options:\n"); fprintf(stdout, "\t-i original sequence [required parameter]\n"); fprintf(stdout, "\t-o reconstructed frames [%s]\n", DEF_OUTFILENAME); fprintf(stdout, "\t-B filename for bitstream [%s]\n", DEF_STREAMNAME); fprintf(stdout, "\t-a image to start at [%d]\n", DEF_START_FRAME); fprintf(stdout, "\t-b image to stop at [%d]\n", DEF_STOP_FRAME); fprintf(stdout, "\t-x ( ) coding format [%d]\n", DEF_CODING_FORMAT); fprintf(stdout, "\t n=1: SQCIF n=2: QCIF n=3: CIF n=4: 4CIF n=5: 16CIF n=6: Custom (12:11 PAR)\n"); fprintf(stdout, "\t 128x96 176x144 352x288 704x576 1408x1152 pels x lines\n"); fprintf(stdout, "\t-s (0..15) integer pel search window [%d]\n", DEF_SEEK_DIST); fprintf(stdout, "\t-q (1..31) quantization parameter QP [%d]\n", DEF_INTER_QUANT); fprintf(stdout, "\t-A (1..31) QP for first frame [%d]\n", DEF_INTRA_QUANT); fprintf(stdout, "\t-r target bitrate in bits/s, default is variable bitrate\n"); fprintf(stdout, "\t -C Rate control method [%d]\n", DEF_RC_METHOD); fprintf(stdout, "\t-k frames to skip between each encoded frame [%d]\n", DEF_FRAMESKIP); fprintf(stdout, "\t-Z reference frame rate (25 or 30 fps) [%.1f]\n", DEF_REF_FRAME_RATE); fprintf(stdout, "\t-l frames skipped in original compared to reference frame rate [%d]\n", DEF_ORIG_SKIP); fprintf(stdout, "\t-e original sequence has n bytes header [%d]\n", DEF_HEADERLENGTH); fprintf(stdout, "\t-g insert sync after each n GOB (slice) [%d]\n", DEF_INSERT_SYNC); fprintf(stdout, "\t zero above means no extra syncs inserted\n"); fprintf(stdout, "\t-w write difference image to file \"%s\" [%s]\n", DEF_DIFFILENAME, DEF_WRITE_DIFF ? "ON" : "OFF"); fprintf(stdout, "\t-m write repeated reconstructed frames to disk [%s]\n", DEF_WRITE_REPEATED ? "ON" : "OFF"); fprintf(stdout, "\t-t write trace to tracefile trace.intra/trace [%s]\n", DEF_WRITE_TRACE ? "ON" : "OFF"); fprintf(stdout, "\t-D use unrestricted motion vector mode (annex D) [%s]\n", DEF_UMV_MODE ? "ON" : "OFF"); fprintf(stdout, "\t n=1: H.263 n=2: H.263+\n"); fprintf(stdout, "\t-E use syntax-based arithmetic coding (annex E) [%s]\n", DEF_SAC_MODE ? "ON" : "OFF"); fprintf(stdout, "\t-F use advanced prediction mode (annex F) [%s]\n", DEF_ADV_MODE ? "ON" : "OFF"); fprintf(stdout, "\t-G use PB-frames (annex G) [%s]\n", DEF_PBF_MODE ? "ON" : "OFF"); fprintf(stdout, "\t -U (0..3) BQUANT parameter [%d]\n", DEF_BQUANT); fprintf(stdout, "\t-M use improved PB-frames (annex M) [%s]\n", DEF_PBF_MODE ? "ON" : "OFF"); fprintf(stdout, "\t-I use advanced intra coding mode (annex I) [%s]\n", DEF_AIC_MODE ? "ON" : "OFF"); fprintf(stdout, "\t-J use deblocking filter (annex J) [%s]\n", DEF_DF_MODE ? "ON" : "OFF"); /*fprintf(stdout,"\t-K use slice structure (annex K) [%s]\n", DEF_SS_MODE ? "ON" : "OFF"); fprintf(stdout,"\t-N use reference picture selection mode (annex N) [%s]\n", DEF_RPS_MODE ? "ON" : "OFF"); */ fprintf(stdout, "\t-c frames to select number of true B pictures between P pictures (annex O) [%d]\n", DEF_TEMP_SCAL); fprintf(stdout, "\t-d to set QP for true B pictures (annex O) [%d]\n", DEF_TRUE_B_QUANT); fprintf(stdout, "\t-i enhancement layer sequence\n"); fprintf(stdout, "\t-u to select SNR or spatial scalability mode (annex O) [%s]\n", DEF_SNR_SPAT_SCAL_MODE ? "ON" : "OFF"); fprintf(stdout, "\t n=1: SNR n=3: SPATIAL(horiz) n=5: SPATIAL(vert) n=7: SPATIAL(both)\n"); fprintf(stdout, "\t-v to set QP for enhancement layer (annex O) [%d]\n", DEF_EI_EP_QUANT); /* fprintf(stdout,"\t-O use SNR/spatial scalability (annex O) [%s]\n", DEF_SNRSS_TYPE ? "ON" : "OFF"); fprintf(stdout,"\t-P use reference picture resampling mode (annex P) [%s]\n", DEF_RPR_MODE ? "ON" : "OFF"); fprintf(stdout,"\t-Q use reduced resolution update mode (annex Q) [%s]\n", DEF_RRU_MODE ? "ON" : "OFF"); fprintf(stdout,"\t-R use independently segmented decoding mode (annex R) [%s]\n", DEF_ISD_MODE ? "ON" : "OFF"); */ fprintf(stdout, "\t-S use alternative inter vlc mode (annex S) [%s]\n", DEF_AIV_MODE ? "ON" : "OFF"); fprintf(stdout, "\t-T use modified quantization mode (annex T) [%s]\n", DEF_MQ_MODE ? "ON" : "OFF"); fprintf(stdout, "\t-h Prints help\n"); fprintf(stdout, "\n\tDefault filenames and other options in square brackets \n\tare chosen in config.h\n"); return; } /********************************************************************** * * Name: PrintResult * Description: add bits and prints results * * Input: Bits struct * * Returns: * Side effects: * * Date: 940116 Author: Karl.Lillevold@nta.no * ***********************************************************************/ void PrintResult(Bits * bits, int num_units, int num) { fprintf(stdout, "# intra : %d\n", bits->no_intra / num_units); fprintf(stdout, "# inter : %d\n", bits->no_inter / num_units); fprintf(stdout, "# inter4v : %d\n", bits->no_inter4v / num_units); fprintf(stdout, "--------------\n"); fprintf(stdout, "Coeff_Y: %d\n", bits->Y / num); fprintf(stdout, "Coeff_C: %d\n", bits->C / num); fprintf(stdout, "Vectors: %d\n", bits->vec / num); fprintf(stdout, "CBPY : %d\n", bits->CBPY / num); fprintf(stdout, "MCBPC : %d\n", bits->CBPCM / num); fprintf(stdout, "MODB : %d\n", bits->MODB / num); fprintf(stdout, "CBPB : %d\n", bits->CBPB / num); fprintf(stdout, "COD : %d\n", bits->COD / num); fprintf(stdout, "DQUANT : %d\n", bits->DQUANT / num); if (advanced_intra_coding) fprintf(stdout, "INTRA_MODE: %d\n", bits->INTRA_MODE / num); fprintf(stdout, "header : %d\n", bits->header / num); fprintf(stdout, "==============\n"); fprintf(stdout, "Total : %d\n", bits->total / num); fprintf(stdout, "\n"); return; } void PrintSNR(Results * res, int num) { fprintf(stdout, "SNR_Y : %.2f\n", res->SNR_l / num); fprintf(stdout, "SNR_Cb : %.2f\n", res->SNR_Cb / num); fprintf(stdout, "SNR_Cr : %.2f\n", res->SNR_Cr / num); fprintf(stdout, "--------------\n"); return; } void InitializeCoder(Pict * pic) { /* Default variable values */ adv_pred = DEF_ADV_MODE; syntax_arith_coding = DEF_SAC_MODE; pic->unrestricted_mv_mode = DEF_UMV_MODE; mv_outside_frame = DEF_UMV_MODE || DEF_ADV_MODE; long_vectors = DEF_UMV_MODE; pb_frames = DEF_PBF_MODE; /* h263+ options */ improved_pb_frames = DEF_IM_PBF_MODE; advanced_intra_coding = DEF_AIC_MODE; deblocking_filter = DEF_DF_MODE; slice_structure = DEF_SS_MODE; pic->reference_picture_selection = DEF_RPS_MODE; independently_segmented_decoding = DEF_ISD_MODE; alternative_inter_vlc = DEF_AIV_MODE; modified_quantization = DEF_MQ_MODE; scalability_mode = DEF_SNR_SPAT_SCAL_MODE; reference_picture_resampling = DEF_RPR_MODE; reduced_resolution_update = DEF_RRU_MODE; successive_B_frames = DEF_TEMP_SCAL; b_picture_quant = DEF_TRUE_B_QUANT; enhancement_layer_quant = DEF_EI_EP_QUANT; B_pictures_to_code = 0; pic->RLNUM = BASE_LAYER_NUM; pic->ELNUM = BASE_LAYER_NUM; pic->BQUANT = DEF_BQUANT; pic->source_format = DEF_CODING_FORMAT; rate_control_method = DEF_RC_METHOD; start_rate_control = DEF_START_RATE_CONTROL; pic->seek_dist = DEF_SEEK_DIST; pic->use_gobsync = DEF_INSERT_SYNC; QP = DEF_INTER_QUANT; QPI = DEF_INTRA_QUANT; ref_frame_rate = (float) DEF_REF_FRAME_RATE; chosen_frameskip = DEF_FRAMESKIP + 1; orig_frameskip = DEF_ORIG_SKIP + 1; seqfilename = (char *) malloc(sizeof(char) * 100); enhance_seqfilename = (char *) malloc(sizeof(char) * 100); streamname = (char *) malloc(sizeof(char) * 100); outputfile = (char *) malloc(sizeof(char) * 100); outputfile_enhance = (char *) malloc(sizeof(char) * 100); diff_filename = DEF_DIFFILENAME; tracefile = (char *) malloc(sizeof(char) * 100); seqfilename[0] = '\0'; enhance_seqfilename[0] = '\0'; strcpy(streamname, DEF_STREAMNAME); strcpy(outputfile, DEF_OUTFILENAME); strcpy(outputfile_enhance, DEF_OUTFILENAME_ENHANCE); mv_outside_frame_old = DEF_UMV_MODE; writediff = DEF_WRITE_DIFF; trace = DEF_WRITE_TRACE; write_repeated = DEF_WRITE_REPEATED; prev_I_P_pic_TR = start = DEF_START_FRAME; end = DEF_STOP_FRAME; targetrate = 0; /* default is variable bit rate (fixed quantizer) will be used */ frames = 0; pframes = 0; bframes = 0; Bframes = 0; total_frames_passed = 0; pic->PB = 0; wcopies = icopies = 1; headerlength = DEF_HEADERLENGTH; pic->TR = 0; pic->QP_mean = (float) 0.0; EPTYPE = 0; pic->UFEP = 1; pic->PCF = 0; pic->TRPI = 0; pic->PEI = 0; pic->MODB = 0; } void ProcessArguments(int argc, char *argv[], Pict * pic) { int i; for (i = 1; i < argc; i++) { if (*(argv[i]) == '-') { switch (*(++argv[i])) { case 'a': prev_I_P_pic_TR = start = atoi(argv[++i]); break; case 'b': end = atoi(argv[++i]); break; case 'c': successive_B_frames = atoi(argv[++i]); EPTYPE = ON; break; case 'd': b_picture_quant = atoi(argv[++i]); break; case 'e': headerlength = atoi(argv[++i]); break; case 'g': pic->use_gobsync = atoi(argv[++i]);; break; case 'H': case 'h': Help(); exit(0); break; case 'i': strcpy(seqfilename, argv[++i]); break; case 'k': chosen_frameskip = atoi(argv[++i]) + 1; break; case 'l': orig_frameskip = atoi(argv[++i]) + 1; break; case 'm': write_repeated = ON; break; case 'o': strcpy(outputfile, argv[++i]); break; case 'q': QP = atoi(argv[++i]); if (QP > 31 || QP < 0) { fprintf(stderr, "QP out of range - clipping it\n"); QP = mmin(31, mmax(0, QP)); } break; case 'r': targetrate = atoi(argv[++i]); break; case 's': pic->seek_dist = atoi(argv[++i]); break; case 't': trace = 1; break; case 'u': scalability_mode = atoi(argv[++i]); EPTYPE = ON; break; case 'v': enhancement_layer_quant = atoi(argv[++i]); break; case 'w': writediff = ON; break; case 'x': pic->source_format = atoi(argv[++i]); if (pic->source_format == SF_CUSTOM) { EPTYPE = 1; pels = atoi(argv[++i]); lines = atoi(argv[++i]); } break; case 'A': QPI = atoi(argv[++i]); if (QPI > 31 || QPI < 0) { fprintf(stderr, "QP out of range - clipping it\n"); QPI = mmin(31, mmax(0, QPI)); } break; case 'B': strcpy(streamname, argv[++i]); break; case 'C': rate_control_method = atoi(argv[++i]); break; case 'D': /* note that the Unrestricted Motion Vector mode turns on * both long_vectors and mv_outside_frame */ pic->unrestricted_mv_mode = ON; mv_outside_frame = ON; long_vectors = ON; if (atoi(argv[++i]) == 2) { /* use H.263+ Annex D (RVLC) */ EPTYPE = ON; } break; case 'E': syntax_arith_coding = ON; break; case 'F': /* note that the Advanced Prediction mode turns on both * advanced (8x8 vectors and OBMC) and mv_outside_frame */ /* the Extended Motion Vector mode is included in the * Unrestricted Motion Vector mode, which of course can be * use together with the Advanced Prediction mode */ overlapping_MC = ON; adv_pred = ON; use_4mv = ON; mv_outside_frame = ON; break; case 'G': pb_frames = ON; break; case 'I': advanced_intra_coding = ON; EPTYPE = ON; break; case 'J': /* see table J.1 in H.263+ standard for dependencies */ deblocking_filter = ON; mv_outside_frame = ON; use_4mv = ON; EPTYPE = ON; break; case 'K': slice_structure = ON; EPTYPE = ON; break; case 'M': improved_pb_frames = ON; EPTYPE = ON; break; case 'N': pic->reference_picture_selection = ON; EPTYPE = ON; break; case 'O': strcpy(enhance_seqfilename, argv[++i]); break; case 'P': reference_picture_resampling = ON; EPTYPE = ON; break; case 'Q': reduced_resolution_update = ON; EPTYPE = ON; break; case 'R': independently_segmented_decoding = ON; EPTYPE = ON; break; case 'S': alternative_inter_vlc = ON; EPTYPE = ON; break; case 'T': modified_quantization = ON; EPTYPE = ON; break; case 'U': pic->BQUANT = atoi(argv[++i]); break; case 'Z': ref_frame_rate = (float) atoi(argv[++i]); break; default: fprintf(stderr, "Illegal option: %c\n", *argv[i]); Help(); exit(-1); break; } } } switch (pic->source_format) { case (SF_SQCIF): fprintf(stdout, "Encoding format: SQCIF (128x96)\n"); pels = 128; lines = 96; break; case (SF_QCIF): fprintf(stdout, "Encoding format: QCIF (176x144)\n"); pels = 176; lines = 144; break; case (SF_CIF): fprintf(stdout, "Encoding format: CIF (352x288)\n"); pels = 352; lines = 288; break; case (SF_4CIF): fprintf(stdout, "Encoding format: 4CIF (704x576)\n"); pels = 704; lines = 576; break; case (SF_16CIF): fprintf(stdout, "Encoding format: 16CIF (1408x1152)\n"); pels = 1408; lines = 1152; break; case (SF_CUSTOM): if ((pels % 16) || (lines % 16)) { fprintf(stdout, "Error: only custom format multiple of 16 supported\n"); exit(-1); } else { fprintf(stdout, "Encoding format: custom (%dx%d)\n", pels, lines); break; } default: fprintf(stderr, "Illegal coding format\n"); exit(-1); } cpels = pels / 2; base_pels = pels; base_lines = lines; enhancement_pels = pels * scal_tab[0][scalability_mode]; enhancement_lines = lines * scal_tab[1][scalability_mode]; if (seqfilename[0] == '\0') { fprintf(stderr, "Required input parameter \'-i \' missing\n"); Help(); exit(-1); } if ((scalability_mode >= 3) && enhance_seqfilename[0] == '\0') { fprintf(stderr, "No enhancement layer input sequence has been specified \'-O \'.\n"); fprintf(stderr, "Ehancement layer sequence will be generated from base layer sequence.\n"); } /* Currently, cannot use frame rate control when using temporal scalability. */ if (successive_B_frames && (targetrate > 0)) { fprintf(stderr, "Warning:"); fprintf(stderr, "Variable frame rate and temporal scalability not supported\n"); fprintf(stderr, "Resetting to fixed frame rate\n"); targetrate = 0; } if (successive_B_frames && (pb_frames || improved_pb_frames)) { fprintf(stderr, "Warning:"); fprintf(stderr, "Encoder supports either PB frames or true B pictures, not both.\n"); exit(-1); } if (successive_B_frames && scalability_mode) { fprintf(stderr, "Warning:"); fprintf(stderr, "Encoder does not yet support multiple scalability options.\n"); exit(-1); } /* check for mode restrictions */ if (syntax_arith_coding && (alternative_inter_vlc || modified_quantization || improved_pb_frames)) { fprintf(stderr, "syntax_arith_coding cannot be used with alternative_inter_vlc, improved pb or modified_quantization options\n"); exit(-1); } /* Open stream for writing */ streamfile = fopen(streamname, "wb"); if (streamname == NULL) { fprintf(stderr, "Unable to open streamfile\n"); exit(-1); } /* Clear output files */ if ((cleared = fopen(outputfile, "wb")) == NULL) { fprintf(stderr, "Couldn't open outputfile: %s\n", outputfile); exit(-1); } else { fclose(cleared); } if (writediff) { if ((cleared = fopen(diff_filename, "wb")) == NULL) { fprintf(stderr, "Couldn't open diff-file: %s\n", diff_filename); exit(-1); } else { fclose(cleared); } } if (QP == 0 || QPI == 0) { fprintf(stderr, "Warning:"); fprintf(stderr, "QP is zero. Bitstream will not be correctly decodable\n"); } if (ref_frame_rate != 25.0 && ref_frame_rate != 30.0) { fprintf(stderr, "Warning: Reference frame rate should be 25 or 30 fps\n"); } /* pb frames and improved pb frames can't be used together */ if (pb_frames && improved_pb_frames) { fprintf(stdout, "PB frames option can't be used with Improved pb frames option\n"); fprintf(stdout, "PB frames option is ignored\n"); } pic->target_frame_rate = (ref_frame_rate / (orig_frameskip * chosen_frameskip)); return; } void DeterminePictureType(int *frame_no, Pict * pic, int P_skip, int B_skip, int i) { if (0 == i) { /* Intra */ pic->picture_coding_type = PCT_INTRA; *frame_no = prev_I_P_frame_no = start; prev_I_P_pic_TR = pic->TR = prev_I_P_pic_TR; } else { if ((scalability_mode) && (PCT_INTER == prev_pict_type || PCT_INTRA == prev_pict_type)) { /* EI or EP pictures */ pic->picture_coding_type = (PCT_INTRA == prev_pict_type) ? PCT_EI : PCT_EP; *frame_no = prev_I_P_frame_no; pic->TR = prev_I_P_pic_TR; } else { if (successive_B_frames) { if (B_pictures_to_code) { /* B picture */ pic->picture_coding_type = PCT_B; *frame_no = prev_I_P_frame_no - (B_pictures_to_code * B_skip); --B_pictures_to_code; pic->TR = (prev_I_P_pic_TR + ((successive_B_frames - B_pictures_to_code) * (B_skip * orig_frameskip))) % 256; pic->TRB = pic->TR - prev_I_P_pic_TR; TRP = P_skip; } else { /* P picture */ if (PCT_B == prev_pict_type) { prev_I_P_pic_TR = pic->TR + B_skip; } B_pictures_to_code = successive_B_frames; if (prev_I_P_frame_no + P_skip <= end) { pic->picture_coding_type = PCT_INTER; *frame_no = prev_I_P_frame_no = prev_I_P_frame_no + P_skip; pic->TR = (prev_I_P_pic_TR + (P_skip * orig_frameskip)) % 256; } else { *frame_no = prev_I_P_frame_no; pic->picture_coding_type = -1; pic->TR = prev_I_P_pic_TR; } } } else { if (pb_frames || improved_pb_frames) { if (prev_I_P_frame_no + P_skip > end) { *frame_no = prev_I_P_frame_no; pic->picture_coding_type = -1; pic->TR = prev_I_P_pic_TR; } else { if (PCT_INTRA == prev_pict_type || P_skip > 8 || (prev_I_P_frame_no + 2 * P_skip) > end) { /* If previous picture is INTRA || the temporal reference of P thus the temporal reference of B is larger than 8 || there are not enough frames left to code as PB than code the next picture as P picture */ pic->PB = 0; pic->picture_coding_type = PCT_INTER; *frame_no = prev_I_P_frame_no = prev_I_P_frame_no + P_skip; prev_I_P_pic_TR = pic->TR = (prev_I_P_pic_TR + (P_skip * orig_frameskip)) % 256; } else { /* PB or IPB picture */ pic->PB = (improved_pb_frames) ? IM_PB_FRAMES : PB_FRAMES; pic->picture_coding_type = (improved_pb_frames) ? PCT_IPB : PCT_PB; *frame_no = prev_I_P_frame_no + P_skip; prev_I_P_frame_no += 2 * P_skip; prev_I_P_pic_TR = pic->TR = (prev_I_P_pic_TR + (2 * P_skip * orig_frameskip)) % 256; } } } else { /* P picture */ pic->picture_coding_type = PCT_INTER; *frame_no = prev_I_P_frame_no = prev_I_P_frame_no + P_skip; prev_I_P_pic_TR = pic->TR = (prev_I_P_pic_TR + (P_skip * orig_frameskip)) % 256; } } } } #ifndef VIC if (*frame_no > end) { pic->picture_coding_type = -1; pic->TR = prev_I_P_pic_TR; } #endif } void CalculateStatistics(PictImage * curr_image, PictImage * curr_recon, PictImage * pb_b_image, PictImage * pb_b_recon, Bits * bits, int QP, Pict * pic) { fprintf(stdout, "done\n"); ComputeSNR(curr_image, curr_recon, res, pic->picture_coding_type, writediff); fflush(stdout); if (arith_used) { bits->header += encoder_flush(); arith_used = 0; } bits->header += alignbits(); /* pictures shall be byte aligned */ AddBitsPicture(bits); #ifndef VIC switch (pic->picture_coding_type) { case PCT_INTRA: fprintf(stdout, "Average Intra QP: %d\n", QP); AddRes(intra_res, res, pic); AddBits(intra_bits, bits); break; case PCT_INTER: fprintf(stdout, "Results for P-frame:\n"); AddRes(inter_res, res, pic); fprintf(stdout, "Average Inter QP: %5.2f\n", pic->QP_mean); AddBits(inter_bits, bits); AddBits(total_bits, bits); break; case PCT_PB: case PCT_IPB: fprintf(stdout, "Results for P component of PB frame:\n"); AddRes(inter_res, res, pic); PrintSNR(res, 1); ComputeSNR(pb_b_image, pb_b_recon, res, pic->picture_coding_type, writediff); fprintf(stdout, "Results for B component of PB frame:\n"); AddRes(pb_res, res, pic); fprintf(stdout, "Average P component QP: %d\n", QP); fprintf(stdout, "Average B component BQUANT: %d\n", pic->BQUANT); AddBits(pb_bits, bits); AddBits(total_bits, bits); break; case PCT_B: fprintf(stdout, "Results for true B-frame:\n"); AddRes(b_res, res, pic); fprintf(stdout, "Average B QP: %d\n", QP); AddBits(b_bits, bits); AddBits(total_bits, bits); break; case PCT_EI: fprintf(stdout, "Results for EI frame:\n"); AddRes(ei_res, res, pic); AddRes(scal_res, res, pic); fprintf(stdout, "Average enhancement layer (EI) QP: %d\n", QP); AddBits(ei_bits, bits); AddBits(scal_bits, bits); break; case PCT_EP: fprintf(stdout, "Results for EP frame:\n"); AddRes(ep_res, res, pic); AddRes(scal_res, res, pic); fprintf(stdout, "Average enhancement layer (EP) QP: %d\n", QP); AddBits(ep_bits, bits); AddBits(scal_bits, bits); break; default: break; } PrintSNR(res, 1); PrintResult(bits, 1, 1); #endif } PictImage * UpsampleReferenceLayerPicture(PictImage * base_image) { PictImage *upsampled_image; int size; size = enhancement_pels * enhancement_lines; if ((upsampled_image = (PictImage *) malloc(sizeof(PictImage))) == NULL) { fprintf(stderr, "Couldn't allocate (PictImage *)\n"); exit(-1); } if ((upsampled_image->lum = (unsigned char *) malloc(sizeof(char) * size)) == NULL) { fprintf(stderr, "Couldn't allocate memory for luminance\n"); exit(-1); } if ((upsampled_image->Cr = (unsigned char *) malloc(sizeof(char) * size / 4)) == NULL) { fprintf(stderr, "Couldn't allocate memory for Cr\n"); exit(-1); } if ((upsampled_image->Cb = (unsigned char *) malloc(sizeof(char) * size / 4)) == NULL) { fprintf(stderr, "Couldn't allocate memory for Cb\n"); exit(-1); } UpsampleComponent(base_image->lum, upsampled_image->lum, base_pels, base_lines); UpsampleComponent(base_image->Cr, upsampled_image->Cr, base_pels / 2, base_lines / 2); UpsampleComponent(base_image->Cb, upsampled_image->Cb, base_pels / 2, base_lines / 2); return (upsampled_image); } void UpsampleComponent(unsigned char *base, unsigned char *enhanced, int horiz, int vert) { int i, j; unsigned char *base_next, *enhanced_next, *enhanced_origin; enhanced_origin = enhanced; switch (scalability_mode) { case SPATIAL_SCALABILITY_H: /* Rows */ for (j = 0; j < vert; j++) { /* First column of rows */ *enhanced++ = *base; for (i = 1; i < horiz; i++) { *enhanced++ = (3 * *base + *(base + 1) + 2) >> 2; *enhanced++ = (*base + 3 * *(base + 1) + 2) >> 2; base++; } /* Last column of rows */ *enhanced++ = *base++; } break; case SPATIAL_SCALABILITY_V: /* First row */ for (i = 0; i < horiz; i++) { *enhanced++ = *base++; } enhanced_next = enhanced + horiz; base = base - horiz; base_next = base + horiz; /* Rows */ for (j = 0; j < vert - 1; j++) { for (i = 0; i < horiz; i++) { *enhanced++ = (3 * *base + *(base_next) + 2) >> 2; *enhanced_next++ = (*base + 3 * *(base_next) + 2) >> 2; base++; base_next++; } enhanced = enhanced + horiz; enhanced_next = enhanced + horiz; } /* Last row */ for (i = 0; i < horiz; i++) { *enhanced++ = *base++; } break; case SPATIAL_SCALABILITY_HV: /* Top left corner pel */ *enhanced++ = *base; /* First row */ for (i = 1; i < horiz; i++) { *enhanced++ = (3 * *base + *(base + 1) + 2) >> 2; *enhanced++ = (*base + 3 * *(base + 1) + 2) >> 2; base++; } /* Top right corner pel */ *enhanced++ = *base++; enhanced_next = enhanced + (horiz << 1); base = base - horiz; base_next = base + horiz; /* Rows */ for (j = 0; j < vert - 1; j++) { /* First column of rows */ *enhanced++ = (3 * *base + *(base_next) + 2) >> 2; *enhanced_next++ = (*base + 3 * *(base_next) + 2) >> 2; for (i = 1; i < horiz; i++) { *enhanced++ = (9 * *base + 3 * *(base + 1) + 3 * *base_next + *(base_next + 1) + 8) >> 4; *enhanced++ = (3 * *base + 9 * *(base + 1) + *base_next + 3 * *(base_next + 1) + 8) >> 4; *enhanced_next++ = (3 * *base + *(base + 1) + 9 * *base_next + 3 * *(base_next + 1) + 8) >> 4; *enhanced_next++ = (*base + 3 * *(base + 1) + 3 * *base_next + 9 * *(base_next + 1) + 8) >> 4; base++; base_next++; } /* Last column of rows */ *enhanced++ = (3 * *base + *(base_next) + 2) >> 2; *enhanced_next++ = (*base + 3 * *(base_next) + 2) >> 2; enhanced = enhanced + (horiz << 1); enhanced_next = enhanced + (horiz << 1); base++; base_next++; } /* Bottom left corner pel */ *enhanced++ = *base; /* Last row */ for (i = 1; i < horiz; i++) { *enhanced++ = (3 * *base + *(base + 1) + 2) >> 2; *enhanced++ = (*base + 3 * *(base + 1) + 2) >> 2; base++; } /* Bottom right corner pel */ *enhanced = *base; break; default: break; } } int FrameLayerRC(Pict * pic) { int frameskip; switch (rate_control_method) { case NO: frameskip = chosen_frameskip; break; case TMN5_RC: case TMN8_RC: CommBacklog = mmax(0, CommBacklog + (int) (bits->total - (float) pic->bit_rate / ((pic->PB) ? (pic->target_frame_rate / 2) : (pic->target_frame_rate)))); frameskip = 1; while (CommBacklog > ((float) pic->bit_rate / pic->target_frame_rate)) { CommBacklog = mmax(0, (int) (CommBacklog - (float) pic->bit_rate / pic->target_frame_rate)); frameskip += 1; } frameskip = (int) (frameskip * pic->src_frame_rate / pic->target_frame_rate); break; case OFFLINE_RC: /* Aim for the targetrate with a once per frame rate control scheme */ if (frame_no - start > (end - start) * start_rate_control / 100.0) /* when generating the MPEG-4 anchors, rate control was started after 70% of the sequence was finished. Set start_rate_control with option "-R " */ pic->QUANT = FrameUpdateQP(total_bits->total + intra_bits->total, bits->total, (end - frame_no) / chosen_frameskip + ((pic->PB) ? 1 : 0), QP, targetrate, seconds); frameskip = chosen_frameskip; break; default: break; } if (frameskip > 256) { fprintf(stderr, "Warning: frameskip > 256\n"); } return frameskip; }