Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / mpeg2enc / putpic.c
diff --git a/cinelerra-5.1/mpeg2enc/putpic.c b/cinelerra-5.1/mpeg2enc/putpic.c
new file mode 100644 (file)
index 0000000..ed41834
--- /dev/null
@@ -0,0 +1,506 @@
+/* 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 <stdio.h>
+#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<<block_count) - 1;
+                               }
+                               else
+                               {
+//printf("putpic 4 %p %d\n", picture->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);
+}