2 /**************************************************************************
4 * This code is developed by Adam Li. This software is an *
5 * implementation of a part of one or more MPEG-4 Video tools as *
6 * specified in ISO/IEC 14496-2 standard. Those intending to use this *
7 * software module in hardware or software products are advised that its *
8 * use may infringe existing patents or copyrights, and any such use *
9 * would be at such party's own risk. The original developer of this *
10 * software module and his/her company, and subsequent editors and their *
11 * companies (including Project Mayo), will have no liability for use of *
12 * this software or modifications or derivatives thereof. *
14 * Project Mayo gives users of the Codec a license to this software *
15 * module or modifications thereof for use in hardware or software *
16 * products claiming conformance to the MPEG-4 Video Standard as *
17 * described in the Open DivX license. *
19 * The complete Open DivX license can be found at *
20 * http://www.projectmayo.com/opendivx/license.php . *
22 **************************************************************************/
24 /**************************************************************************
26 * encore.c, MPEG-4 Encoder Core Engine
28 * Copyright (C) 2001 Project Mayo
32 * DivX Advance Research Center <darc@projectmayo.com>
34 **************************************************************************/
36 /* This file contains encore(), which is the main entrance function for */
37 /* Encoder Core Engine. It also contains the functions to initialize the */
38 /* parameters, and redirect the output stream */
45 #include "bitstream.h"
46 #include "vm_common_defs.h"
50 typedef struct _REFERENCE
56 long rc_reaction_period
;
57 long rc_reaction_ratio
;
58 long max_key_interval
;
66 long curr_run
; /* the current run before the last key frame */
68 Vop
*current
; /* the current frame to be encoded */
69 Vop
*reference
; /* the reference frame - reconstructed previous frame */
70 Vop
*reconstruct
; /* intermediate reconstructed frame - used in inter */
71 Vop
*error
; /* intermediate error frame - used in inter to hold prediction error */
73 struct _REFERENCE
*pnext
;
77 int max_quantizer
, min_quantizer
;
79 /* private functions used only in this file */
80 void init_vol_config(VolConfig
*vol_config
);
81 void init_vop(Vop
*vop
);
82 Int
get_fcode (Int sr
);
83 int PutVoVolHeader(int vol_width
, int vol_height
, int time_increment_resolution
, float frame_rate
);
84 int YUV2YUV (int x_dim
, int y_dim
, void *yuv
, void *y_out
, void *u_out
, void *v_out
);
87 // Set global variables for an encoding session
88 void encore_set_global(ENC_PARAM
*param
)
93 int encore(unsigned long handle
,
94 unsigned long enc_opt
,
98 static REFERENCE
*ref
= NULL
;
99 static VolConfig
*vol_config
;
100 // a link list to keep the reference frame for all instances
102 REFERENCE
*ref_curr
, *ref_last
= NULL
;
103 int x_dim
, y_dim
, size
, length
;
107 ref_curr
= ref_last
= ref
;
109 //printf("encore 1\n");
110 while (ref_curr
!= NULL
)
112 if (ref_curr
->handle
== handle
) break;
114 ref_curr
= ref_last
->pnext
;
116 // create a reference for the new handle when no match is found
117 if (ref_curr
== NULL
)
119 if (enc_opt
& ENC_OPT_RELEASE
) return ENC_OK
;
120 ref_curr
= (REFERENCE
*)malloc(sizeof(REFERENCE
));
121 ref_curr
->handle
= handle
;
123 ref_curr
->curr_run
= 0;
124 ref_curr
->pnext
= NULL
;
125 if (ref
) ref_last
->pnext
= ref_curr
;
128 //printf("encore 1\n");
129 // initialize for a handle if requested
130 if (enc_opt
& ENC_OPT_INIT
)
133 ftrace
= fopen("trace.txt", "w");
140 // initializing rate control
141 ref_curr
->framerate
= ((ENC_PARAM
*)param1
)->framerate
;
142 ref_curr
->bitrate
= ((ENC_PARAM
*)param1
)->bitrate
;
143 ref_curr
->rc_period
= ((ENC_PARAM
*)param1
)->rc_period
;
144 ref_curr
->rc_reaction_period
= ((ENC_PARAM
*)param1
)->rc_reaction_period
;
145 ref_curr
->rc_reaction_ratio
= ((ENC_PARAM
*)param1
)->rc_reaction_ratio
;
146 ref_curr
->x_dim
= ((ENC_PARAM
*)param1
)->x_dim
;
147 ref_curr
->y_dim
= ((ENC_PARAM
*)param1
)->y_dim
;
148 ref_curr
->max_key_interval
= ((ENC_PARAM
*)param1
)->max_key_interval
;
149 ref_curr
->search_range
= ((ENC_PARAM
*)param1
)->search_range
;
150 ref_curr
->max_quantizer
= ((ENC_PARAM
*)param1
)->max_quantizer
;
151 ref_curr
->min_quantizer
= ((ENC_PARAM
*)param1
)->min_quantizer
;
153 ref_curr
->current
= AllocVop(ref_curr
->x_dim
, ref_curr
->y_dim
);
154 ref_curr
->reference
= AllocVop(ref_curr
->x_dim
+ 2 * 16,
155 ref_curr
->y_dim
+ 2 * 16);
156 ref_curr
->reconstruct
= AllocVop(ref_curr
->x_dim
, ref_curr
->y_dim
);
157 ref_curr
->error
= AllocVop(ref_curr
->x_dim
, ref_curr
->y_dim
);
158 init_vop(ref_curr
->current
);
159 init_vop(ref_curr
->reference
);
160 init_vop(ref_curr
->reconstruct
);
161 init_vop(ref_curr
->error
);
162 ref_curr
->reference
->hor_spat_ref
= -16;
163 ref_curr
->reference
->ver_spat_ref
= -16;
164 SetConstantImage(ref_curr
->reference
->y_chan
, 0);
166 vol_config
= (VolConfig
*)malloc(sizeof(VolConfig
));
167 init_vol_config(vol_config
);
168 vol_config
->frame_rate
= ref_curr
->framerate
;
169 vol_config
->bit_rate
= ref_curr
->bitrate
;
171 RateCtlInit(8 /* initial quant*/, vol_config
->bit_rate
/ vol_config
->frame_rate
,
172 ref_curr
->rc_period
, ref_curr
->rc_reaction_period
, ref_curr
->rc_reaction_ratio
);
176 //printf("encore 1\n");
177 // release the reference associated with the handle if requested
178 if (enc_opt
& ENC_OPT_RELEASE
)
180 if (ref_curr
== ref
) ref
= NULL
;
181 else ref_last
->pnext
= ref_curr
->pnext
;
183 if (ref_curr
->current
) FreeVop(ref_curr
->current
);
184 if (ref_curr
->reference
) FreeVop(ref_curr
->reference
);
185 if (ref_curr
->reconstruct
) FreeVop(ref_curr
->reconstruct
);
186 if (ref_curr
->error
) FreeVop(ref_curr
->error
);
197 //printf("encore 1\n");
198 // initialize the parameters (need to be cleaned later)
200 max_quantizer
= ref_curr
->max_quantizer
;
201 min_quantizer
= ref_curr
->min_quantizer
;
203 x_dim
= ref_curr
->x_dim
;
204 y_dim
= ref_curr
->y_dim
;
205 size
= x_dim
* y_dim
;
207 curr
= ref_curr
->current
;
209 curr
->height
= y_dim
;
210 curr
->sr_for
= ref_curr
->search_range
;
211 curr
->fcode_for
= get_fcode(curr
->sr_for
);
213 // do transformation for the input image
214 // this is needed because the legacy MoMuSys code uses short int for each data
215 YUV2YUV(x_dim
, y_dim
, ((ENC_FRAME
*)param1
)->image
,
220 // adjust the rounding_type for the current image
221 curr
->rounding_type
= 1 - ref_curr
->prev_rounding
;
222 //printf("encore 1\n");
224 Bitstream_Init((void *)(((ENC_FRAME
*)param1
)->bitstream
));
225 //printf("encore 1\n");
227 if (ref_curr
->seq
== 0)
229 headerbits
= PutVoVolHeader(x_dim
,
231 curr
->time_increment_resolution
,
232 ref_curr
->framerate
);
234 //printf("encore 1\n");
238 fprintf(ftrace
, "\nCoding frame #%d\n", ref_curr
->seq
);
240 //printf("encore 1 %p %p\n", ref_curr, curr);
242 if (ref_curr
->curr_run
% ref_curr
->max_key_interval
== 0) {
243 curr
->prediction_type
= I_VOP
;
245 fprintf(ftrace
, "This frame is forced to be coded in INTRA.\n");
246 fprintf(ftrace
, "It has been %d frame since the last INTRA.\n", ref_curr
->curr_run
);
249 else curr
->prediction_type
= P_VOP
;
259 //printf("encore 1\n");
260 // Code the image data (YUV) of the current image
263 ref_curr
->reconstruct
,
266 (float)ref_curr
->seq
/ref_curr
->framerate
, // time
268 ((ENC_FRAME
*)param1
)->quant
);
276 length
= Bitstream_Close();
277 ((ENC_FRAME
*)param1
)->length
= length
;
279 //printf("encore 2\n");
280 // update the rate control parameters
281 RateCtlUpdate(length
* 8);
283 ref_curr
->prev_rounding
= curr
->rounding_type
;
285 ref_curr
->curr_run
++;
287 if (curr
->prediction_type
== I_VOP
) {
288 ((ENC_RESULT
*)param2
)->isKeyFrame
= 1;
289 ref_curr
->curr_run
= 1;
291 ((ENC_RESULT
*)param2
)->isKeyFrame
= 0;
292 //printf("encore 3\n");
298 void init_vol_config(VolConfig
*vol_config
)
302 vol_config
->frame_skip
= 1;
303 vol_config
->quantizer
= 8;
304 vol_config
->intra_quantizer
= 8;
305 vol_config
->modulo_time_base
[0] =0;
306 vol_config
->modulo_time_base
[1] =0;
307 vol_config
->frame_rate
= 30;
308 vol_config
->bit_rate
= 800000;
312 void init_vop(Vop
*vop
)
314 /* initialize VOPs */
315 vop
->quant_precision
= 5;
316 vop
->bits_per_pixel
= 8;
317 // vop->time_increment_resolution = 15 ;
318 vop
->time_increment_resolution
= 30000;
319 vop
->intra_acdc_pred_disable
= 0;
320 vop
->intra_dc_vlc_thr
= 0;
323 vop
->fcode_for
= get_fcode(512);
325 vop
->y_chan
->type
= SHORT_TYPE
;
326 vop
->u_chan
->type
= SHORT_TYPE
;
327 vop
->v_chan
->type
= SHORT_TYPE
;
329 vop
->hor_spat_ref
= 0;
330 vop
->ver_spat_ref
= 0;
334 Int
get_fcode (Int sr
)
336 if (sr
<=16) return 1;
337 else if (sr
<=32) return 2;
338 else if (sr
<=64) return 3;
339 else if (sr
<=128) return 4;
340 else if (sr
<=256) return 5;
341 else if (sr
<=512) return 6;
342 else if (sr
<=1024) return 7;
346 int PutVoVolHeader(int vol_width
,
348 int time_increment_resolution
,
352 int bits
, fixed_vop_time_increment
;
354 Bitstream_PutBits(VO_START_CODE_LENGTH
, VO_START_CODE
);
355 Bitstream_PutBits(5, 0); /* vo_id = 0 */
356 written
+= VO_START_CODE_LENGTH
+ 5;
358 Bitstream_PutBits(VOL_START_CODE_LENGTH
, VOL_START_CODE
);
359 Bitstream_PutBits(4, 0); /* vol_id = 0 */
360 written
+= VOL_START_CODE_LENGTH
+ 4;
362 Bitstream_PutBits(1, 0); /* random_accessible_vol = 0 */
363 Bitstream_PutBits(8, 1); /* video_object_type_indication = 1 video */
364 Bitstream_PutBits(1, 1); /* is_object_layer_identifier = 1 */
365 Bitstream_PutBits(4, 2); /* visual_object_layer_ver_id = 2 */
366 Bitstream_PutBits(3, 1); /* visual_object_layer_priority = 1 */
367 written
+= 1 + 8 + 1 + 4 + 3;
369 Bitstream_PutBits(4, 1); /* aspect_ratio_info = 1 */
377 Bitstream_PutBits(1, 0); /* vol_control_parameter = 0 */
378 Bitstream_PutBits(2, 0); /* vol_shape = 0 rectangular */
379 Bitstream_PutBits(1, 1); /* marker */
380 written
+= 4 + 1 + 2 + 1;
382 Bitstream_PutBits(16, time_increment_resolution
);
383 Bitstream_PutBits(1, 1); /* marker */
384 Bitstream_PutBits(1, 1); /* fixed_vop_rate = 1 */
385 bits
= (int)ceil(log((double)time_increment_resolution
)/log(2.0));
387 fixed_vop_time_increment
= (int)(time_increment_resolution
/ frame_rate
+ 0.1);
388 Bitstream_PutBits(bits
, fixed_vop_time_increment
);
389 Bitstream_PutBits(1, 1); /* marker */
390 written
+= 16 + 1 + 1 + bits
+ 1;
392 Bitstream_PutBits(13, vol_width
);
393 Bitstream_PutBits(1, 1); /* marker */
394 Bitstream_PutBits(13, vol_height
);
395 Bitstream_PutBits(1, 1); /* marker */
396 written
+= 13 + 1 + 13 + 1;
398 Bitstream_PutBits(1, 0); /* interlaced = 0 */
399 Bitstream_PutBits(1, 1); /* OBMC_disabled = 1 */
400 Bitstream_PutBits(2, 0); /* vol_sprite_usage = 0 */
401 Bitstream_PutBits(1, 0); /* not_8_bit = 0 */
402 written
+= 1 + 1 + 2 + 1;
404 Bitstream_PutBits(1, 0); /* vol_quant_type = 0 */
405 Bitstream_PutBits(1, 0); /* vol_quarter_pixel = 0 */
406 Bitstream_PutBits(1, 1); /* complexity_estimation_disabled = 1 */
407 Bitstream_PutBits(1, 1); /* resync_marker_disabled = 1 */
408 Bitstream_PutBits(1, 0); /* data_partitioning_enabled = 0 */
409 Bitstream_PutBits(1, 0); /* scalability = 0 */
410 written
+= 1 + 1 + 1 + 1 + 1 + 1;
412 written
+= Bitstream_NextStartCode();
417 int YUV2YUV (int x_dim
, int y_dim
, void *yuv
, void *y_out
, void *u_out
, void *v_out
)
419 // All this conversion does is to turn data from unsigned char to short int,
420 // since legacy MoMuSys uses short int.
428 size
= x_dim
* y_dim
;
429 while (size
--) *(out
++) = *(in
++);
432 size
= x_dim
* y_dim
/ 4;
433 while (size
--) *(out
++) = *(in
++);
436 size
= x_dim
* y_dim
/ 4;
437 while (size
--) *(out
++) = *(in
++);