/* putpic.c, block and motion vector encoding routines */ /* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ /* * Disclaimer of Warranty * * These software programs are available to the user without any license fee or * royalty on an "as is" basis. The MPEG Software Simulation Group 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 MPEG Software Simulation Group does not represent or warrant that the * programs furnished hereunder are free of infringement of any third-party * patents. * * Commercial implementations of MPEG-1 and MPEG-2 video, 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 #include "config.h" #include "global.h" /* output motion vectors (6.2.5.2, 6.3.16.2) * * this routine also updates the predictions for motion vectors (PMV) */ static void putmvs(slice_engine_t *engine, pict_data_s *picture, mbinfo_s *mb, int PMV[2][2][2], int back) { int hor_f_code; int vert_f_code; if( back ) { hor_f_code = picture->back_hor_f_code; vert_f_code = picture->back_vert_f_code; } else { hor_f_code = picture->forw_hor_f_code; vert_f_code = picture->forw_vert_f_code; } if(picture->pict_struct == FRAME_PICTURE) { if(mb->motion_type == MC_FRAME) { /* frame prediction */ putmv(engine, mb->MV[0][back][0] - PMV[0][back][0], hor_f_code); putmv(engine, mb->MV[0][back][1] - PMV[0][back][1], vert_f_code); PMV[0][back][0] = PMV[1][back][0] = mb->MV[0][back][0]; PMV[0][back][1] = PMV[1][back][1] = mb->MV[0][back][1]; } else if (mb->motion_type == MC_FIELD) { /* field prediction */ slice_putbits(engine, mb->mv_field_sel[0][back], 1); putmv(engine, mb->MV[0][back][0] - PMV[0][back][0], hor_f_code); putmv(engine, (mb->MV[0][back][1] >> 1) - (PMV[0][back][1] >> 1), vert_f_code); slice_putbits(engine, mb->mv_field_sel[1][back], 1); putmv(engine, mb->MV[1][back][0] - PMV[1][back][0], hor_f_code); putmv(engine, (mb->MV[1][back][1] >> 1) - (PMV[1][back][1] >> 1), vert_f_code); PMV[0][back][0] = mb->MV[0][back][0]; PMV[0][back][1] = mb->MV[0][back][1]; PMV[1][back][0] = mb->MV[1][back][0]; PMV[1][back][1] = mb->MV[1][back][1]; } else { /* dual prime prediction */ putmv(engine, mb->MV[0][back][0] - PMV[0][back][0], hor_f_code); putdmv(engine, mb->dmvector[0]); putmv(engine, (mb->MV[0][back][1] >> 1) - (PMV[0][back][1] >> 1), vert_f_code); putdmv(engine, mb->dmvector[1]); PMV[0][back][0] = PMV[1][back][0] = mb->MV[0][back][0]; PMV[0][back][1] = PMV[1][back][1] = mb->MV[0][back][1]; } } else { /* field picture */ if(mb->motion_type == MC_FIELD) { /* field prediction */ slice_putbits(engine, mb->mv_field_sel[0][back], 1); putmv(engine, mb->MV[0][back][0] - PMV[0][back][0], hor_f_code); putmv(engine, mb->MV[0][back][1] - PMV[0][back][1], vert_f_code); PMV[0][back][0] = PMV[1][back][0] = mb->MV[0][back][0]; PMV[0][back][1] = PMV[1][back][1] = mb->MV[0][back][1]; } else if(mb->motion_type == MC_16X8) { /* 16x8 prediction */ slice_putbits(engine, mb->mv_field_sel[0][back], 1); putmv(engine, mb->MV[0][back][0] - PMV[0][back][0], hor_f_code); putmv(engine, mb->MV[0][back][1] - PMV[0][back][1], vert_f_code); slice_putbits(engine, mb->mv_field_sel[1][back], 1); putmv(engine, mb->MV[1][back][0] - PMV[1][back][0], hor_f_code); putmv(engine, mb->MV[1][back][1] - PMV[1][back][1], vert_f_code); PMV[0][back][0] = mb->MV[0][back][0]; PMV[0][back][1] = mb->MV[0][back][1]; PMV[1][back][0] = mb->MV[1][back][0]; PMV[1][back][1] = mb->MV[1][back][1]; } else { /* dual prime prediction */ putmv(engine, mb->MV[0][back][0] - PMV[0][back][0], hor_f_code); putdmv(engine, mb->dmvector[0]); putmv(engine, mb->MV[0][back][1] - PMV[0][back][1], vert_f_code); putdmv(engine, mb->dmvector[1]); PMV[0][back][0] = PMV[1][back][0] = mb->MV[0][back][0]; PMV[0][back][1] = PMV[1][back][1] = mb->MV[0][back][1]; } } } void* slice_engine_loop(slice_engine_t *engine) { while(!engine->done) { pthread_mutex_lock(&(engine->input_lock)); if(!engine->done) { pict_data_s *picture = engine->picture; int i, j, k, comp, cc; int mb_type; int PMV[2][2][2]; int cbp, MBAinc = 0; short (*quant_blocks)[64] = picture->qblocks; k = engine->start_row * mb_width; for(j = engine->start_row; j < engine->end_row; j++) { /* macroblock row loop */ //printf("putpic 1\n"); //slice_testbits(engine); for(i = 0; i < mb_width; i++) { mbinfo_s *cur_mb = &picture->mbinfo[k]; int cur_mb_blocks = k * block_count; //pthread_mutex_lock(&test_lock); /* macroblock loop */ if(i == 0) { slice_alignbits(engine); /* slice header (6.2.4) */ if(mpeg1 || vertical_size <= 2800) slice_putbits(engine, SLICE_MIN_START + j, 32); /* slice_start_code */ else { slice_putbits(engine, SLICE_MIN_START + (j & 127), 32); /* slice_start_code */ slice_putbits(engine, j >> 7, 3); /* slice_vertical_position_extension */ } /* quantiser_scale_code */ //printf("putpic 1\n");slice_testbits(engine); slice_putbits(engine, picture->q_scale_type ? map_non_linear_mquant_hv[engine->prev_mquant] : engine->prev_mquant >> 1, 5); slice_putbits(engine, 0, 1); /* extra_bit_slice */ //printf("putpic 1 %d %d %d\n",engine->prev_mquant, map_non_linear_mquant_hv[engine->prev_mquant], engine->prev_mquant >> 1); //slice_testbits(engine); /* reset predictors */ for(cc = 0; cc < 3; cc++) engine->dc_dct_pred[cc] = 0; PMV[0][0][0] = PMV[0][0][1] = PMV[1][0][0] = PMV[1][0][1] = 0; PMV[0][1][0] = PMV[0][1][1] = PMV[1][1][0] = PMV[1][1][1] = 0; MBAinc = i + 1; /* first MBAinc denotes absolute position */ } mb_type = cur_mb->mb_type; /* determine mquant (rate control) */ cur_mb->mquant = ratectl_calc_mquant(engine->ratectl, picture, k); /* quantize macroblock */ //printf("putpic 1\n"); //printf("putpic 1\n"); //slice_testbits(engine); if(mb_type & MB_INTRA) { //printf("putpic 2 %d\n", cur_mb->mquant); quant_intra_hv( picture, picture->blocks[cur_mb_blocks], quant_blocks[cur_mb_blocks], cur_mb->mquant, &cur_mb->mquant ); //printf("putpic 3\n"); cur_mb->cbp = cbp = (1<blocks[cur_mb_blocks], cur_mb_blocks); cbp = (*pquant_non_intra)(picture, picture->blocks[cur_mb_blocks], quant_blocks[cur_mb_blocks], cur_mb->mquant, &cur_mb->mquant); //printf("putpic 5\n"); cur_mb->cbp = cbp; if (cbp) mb_type|= MB_PATTERN; } //printf("putpic 6\n"); //printf("putpic 2\n"); //slice_testbits(engine); /* output mquant if it has changed */ if(cbp && engine->prev_mquant != cur_mb->mquant) mb_type |= MB_QUANT; /* check if macroblock can be skipped */ if(i != 0 && i != mb_width - 1 && !cbp) { /* no DCT coefficients and neither first nor last macroblock of slice */ if(picture->pict_type == P_TYPE && !(mb_type & MB_FORWARD)) { /* P picture, no motion vectors -> skip */ /* reset predictors */ for(cc = 0; cc < 3; cc++) engine->dc_dct_pred[cc] = 0; PMV[0][0][0] = PMV[0][0][1] = PMV[1][0][0] = PMV[1][0][1] = 0; PMV[0][1][0] = PMV[0][1][1] = PMV[1][1][0] = PMV[1][1][1] = 0; cur_mb->mb_type = mb_type; cur_mb->skipped = 1; MBAinc++; k++; continue; } if(picture->pict_type == B_TYPE && picture->pict_struct == FRAME_PICTURE && cur_mb->motion_type == MC_FRAME && ((picture->mbinfo[k - 1].mb_type ^ mb_type) & (MB_FORWARD | MB_BACKWARD)) == 0 && (!(mb_type & MB_FORWARD) || (PMV[0][0][0] == cur_mb->MV[0][0][0] && PMV[0][0][1] == cur_mb->MV[0][0][1])) && (!(mb_type & MB_BACKWARD) || (PMV[0][1][0] == cur_mb->MV[0][1][0] && PMV[0][1][1] == cur_mb->MV[0][1][1]))) { /* conditions for skipping in B frame pictures: * - must be frame predicted * - must be the same prediction type (forward/backward/interp.) * as previous macroblock * - relevant vectors (forward/backward/both) have to be the same * as in previous macroblock */ cur_mb->mb_type = mb_type; cur_mb->skipped = 1; MBAinc++; k++; continue; } if (picture->pict_type == B_TYPE && picture->pict_struct != FRAME_PICTURE && cur_mb->motion_type == MC_FIELD && ((picture->mbinfo[k - 1].mb_type ^ mb_type) & (MB_FORWARD | MB_BACKWARD))==0 && (!(mb_type & MB_FORWARD) || (PMV[0][0][0] == cur_mb->MV[0][0][0] && PMV[0][0][1] == cur_mb->MV[0][0][1] && cur_mb->mv_field_sel[0][0] == (picture->pict_struct == BOTTOM_FIELD))) && (!(mb_type & MB_BACKWARD) || (PMV[0][1][0] == cur_mb->MV[0][1][0] && PMV[0][1][1] == cur_mb->MV[0][1][1] && cur_mb->mv_field_sel[0][1] == (picture->pict_struct == BOTTOM_FIELD)))) { /* conditions for skipping in B field pictures: * - must be field predicted * - must be the same prediction type (forward/backward/interp.) * as previous macroblock * - relevant vectors (forward/backward/both) have to be the same * as in previous macroblock * - relevant motion_vertical_field_selects have to be of same * parity as current field */ cur_mb->mb_type = mb_type; cur_mb->skipped = 1; MBAinc++; k++; continue; } } //printf("putpic 3\n"); //slice_testbits(engine); /* macroblock cannot be skipped */ cur_mb->skipped = 0; /* there's no VLC for 'No MC, Not Coded': * we have to transmit (0,0) motion vectors */ if(picture->pict_type == P_TYPE && !cbp && !(mb_type & MB_FORWARD)) mb_type |= MB_FORWARD; /* macroblock_address_increment */ putaddrinc(engine, MBAinc); MBAinc = 1; putmbtype(engine, picture->pict_type, mb_type); /* macroblock type */ //printf("putpic 3\n"); //slice_testbits(engine); if(mb_type & (MB_FORWARD | MB_BACKWARD) && !picture->frame_pred_dct) slice_putbits(engine, cur_mb->motion_type, 2); //printf("putpic %x %d %d %d\n", mb_type, picture->pict_struct, cbp, picture->frame_pred_dct); if(picture->pict_struct == FRAME_PICTURE && cbp && !picture->frame_pred_dct) slice_putbits(engine, cur_mb->dct_type, 1); if(mb_type & MB_QUANT) { slice_putbits(engine, picture->q_scale_type ? map_non_linear_mquant_hv[cur_mb->mquant] : cur_mb->mquant >> 1, 5); engine->prev_mquant = cur_mb->mquant; } if(mb_type & MB_FORWARD) { /* forward motion vectors, update predictors */ putmvs(engine, picture, cur_mb, PMV, 0); } if(mb_type & MB_BACKWARD) { /* backward motion vectors, update predictors */ putmvs(engine, picture, cur_mb, PMV, 1); } if(mb_type & MB_PATTERN) { putcbp(engine, (cbp >> (block_count - 6)) & 63); if(chroma_format != CHROMA420) slice_putbits(engine, cbp, block_count - 6); } //printf("putpic 4\n"); //slice_testbits(engine); for(comp = 0; comp < block_count; comp++) { /* block loop */ if(cbp & (1 << (block_count - 1 - comp))) { if(mb_type & MB_INTRA) { cc = (comp < 4) ? 0 : (comp & 1) + 1; putintrablk(engine, picture, quant_blocks[cur_mb_blocks + comp], cc); } else putnonintrablk(engine, picture, quant_blocks[cur_mb_blocks + comp]); } } //printf("putpic 5\n"); //slice_testbits(engine); //sleep(1); /* reset predictors */ if(!(mb_type & MB_INTRA)) for(cc = 0; cc < 3; cc++) engine->dc_dct_pred[cc] = 0; if(mb_type & MB_INTRA || (picture->pict_type == P_TYPE && !(mb_type & MB_FORWARD))) { PMV[0][0][0] = PMV[0][0][1] = PMV[1][0][0] = PMV[1][0][1] = 0; PMV[0][1][0] = PMV[0][1][1] = PMV[1][1][0] = PMV[1][1][1] = 0; } cur_mb->mb_type = mb_type; k++; //pthread_mutex_unlock(&test_lock); } } } pthread_mutex_unlock(&(engine->output_lock)); } } /* quantization / variable length encoding of a complete picture */ void putpict(pict_data_s *picture) { int i, prev_mquant; for(i = 0; i < processors; i++) { ratectl_init_pict(ratectl[i], picture); /* set up rate control */ } /* picture header and picture coding extension */ putpicthdr(picture); if(!mpeg1) putpictcodext(picture); /* Flush buffer before switching to slice mode */ alignbits(); /* Start loop */ for(i = 0; i < processors; i++) { slice_engines[i].prev_mquant = ratectl_start_mb(ratectl[i], picture); slice_engines[i].picture = picture; slice_engines[i].ratectl = ratectl[i]; slice_initbits(&slice_engines[i]); pthread_mutex_unlock(&(slice_engines[i].input_lock)); } /* Wait for completion and write slices */ for(i = 0; i < processors; i++) { pthread_mutex_lock(&(slice_engines[i].output_lock)); slice_finishslice(&slice_engines[i]); } for(i = 0; i < processors; i++) ratectl_update_pict(ratectl[i], picture); } void start_slice_engines() { int i; int rows_per_processor = (int)((float)mb_height2 / processors + 0.5); int current_row = 0; pthread_attr_t attr; pthread_mutexattr_t mutex_attr; pthread_mutexattr_init(&mutex_attr); pthread_attr_init(&attr); // pthread_mutex_init(&test_lock, &mutex_attr); slice_engines = calloc(1, sizeof(slice_engine_t) * processors); for(i = 0; i < processors; i++) { slice_engines[i].start_row = current_row; current_row += rows_per_processor; if(current_row > mb_height2) current_row = mb_height2; slice_engines[i].end_row = current_row; pthread_mutex_init(&(slice_engines[i].input_lock), &mutex_attr); pthread_mutex_lock(&(slice_engines[i].input_lock)); pthread_mutex_init(&(slice_engines[i].output_lock), &mutex_attr); pthread_mutex_lock(&(slice_engines[i].output_lock)); slice_engines[i].done = 0; pthread_create(&(slice_engines[i].tid), &attr, (void*)slice_engine_loop, &slice_engines[i]); } } void stop_slice_engines() { int i; for(i = 0; i < processors; i++) { slice_engines[i].done = 1; pthread_mutex_unlock(&(slice_engines[i].input_lock)); pthread_join(slice_engines[i].tid, 0); pthread_mutex_destroy(&(slice_engines[i].input_lock)); pthread_mutex_destroy(&(slice_engines[i].output_lock)); if(slice_engines[i].slice_buffer) free(slice_engines[i].slice_buffer); } free(slice_engines); // pthread_mutex_destroy(&test_lock); }