8 #ifdef HAVE_DIVX4ENCORE
10 #include "codec-cfg.h"
17 #include "img_format.h"
21 /* About XviD VBR Library, Edouard Gomez (GomGom) said:
22 <GomGom> header bytes == frame header bytes :-)
23 <GomGom> total bytes = frame bytes == texture + header
24 <GomGom> quant = quant returned by xvidcore
25 <GomGom> it's possible that xvid lowers or increases the passed quant because of lumimasking
26 <GomGom> kblks = blocks coded as intra blocks
27 <GomGom> mblks = blocks coded as predicted blocks
28 <GomGom> ublks = skipped blocks
29 <GomGom> at the moemnt le vbr lib uses total bytes, and quant
30 <GomGom> so it's easy to use it with divx5 (wo bframes)
31 <klOUg> bframes breaks what assumptions?
32 <GomGom> quant estimation for next frame
33 <GomGom> because of the bframe quant multiplier given to divx5
34 <GomGom> that the vbr lib does not "know"
37 //===========================================================================//
40 extern char* passtmpfile
;
48 #ifndef ENCORE_MAJOR_VERSION
49 #define ENCORE_MAJOR_VERSION 4000
52 #if ENCORE_MAJOR_VERSION < 5200
53 #include "divx4_vbr.h"
60 #if ENCORE_MAJOR_VERSION >= 5200
63 ENC_PARAM divx4_param
;
67 static int vbrpass
= -1;
68 static int vbrdebug
= 0;
73 m_option_t divx4opts_conf
[]={
74 {"pass", &pass
, CONF_TYPE_INT
, CONF_RANGE
,0,2, NULL
},
75 {"br", &divx4_param
.bitrate
, CONF_TYPE_INT
, CONF_RANGE
, 4, 24000000, NULL
},
76 #if ENCORE_MAJOR_VERSION < 5200
77 {"rc_period", &divx4_param
.rc_period
, CONF_TYPE_INT
, 0,0,0, NULL
},
78 {"rc_reaction_period", &divx4_param
.rc_reaction_period
, CONF_TYPE_INT
, 0,0,0, NULL
},
79 {"rc_reaction_ratio", &divx4_param
.rc_reaction_ratio
, CONF_TYPE_INT
, 0,0,0, NULL
},
80 {"min_quant", &divx4_param
.min_quantizer
, CONF_TYPE_INT
, CONF_RANGE
,0,32, NULL
},
81 {"max_quant", &divx4_param
.max_quantizer
, CONF_TYPE_INT
, CONF_RANGE
,0,32, NULL
},
83 {"key", &divx4_param
.max_key_interval
, CONF_TYPE_INT
, CONF_MIN
,0,0, NULL
},
84 {"deinterlace", &divx4_param
.deinterlace
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
85 {"q", &divx4_param
.quality
, CONF_TYPE_INT
, CONF_RANGE
, 1, 5, NULL
},
86 {"crispness", &divx4_crispness
, CONF_TYPE_INT
, CONF_RANGE
,0,100, NULL
},
87 #if ENCORE_MAJOR_VERSION >= 5010
88 #if ENCORE_MAJOR_VERSION >= 5200
89 /* rate control modes:
91 1 (1-pass constant quality)
92 2 (VBV multipass 1st-pass)
93 3 (VBV multipass nth-pass)
97 7 (1-pass constant frame size)
99 {"vbr", &divx4_param
.vbr_mode
, CONF_TYPE_INT
, CONF_RANGE
,0,7, NULL
},
100 {"bidirect", &divx4_param
.use_bidirect
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
101 {"key_frame_threshold", &divx4_param
.key_frame_threshold
, CONF_TYPE_INT
, CONF_RANGE
,1,100, NULL
},
102 /* default values from the DivX Help Guide:
103 bitrate size occupancy
104 128000 262144 196608 (Handheld)
105 768000 1048576 786432 (Portable)
106 4000000 3145728 2359296 (Home Theatre)
107 8000000 6291456 4718592 (High Definition)
108 Do not mess with these values unless you are absolutely sure of what you are doing!
110 {"vbv_bitrate", &divx4_param
.vbv_bitrate
, CONF_TYPE_INT
, 0,0,0, NULL
},
111 {"vbv_size", &divx4_param
.vbv_size
, CONF_TYPE_INT
, 0,0,0, NULL
},
112 {"vbv_occupancy", &divx4_param
.vbv_occupancy
, CONF_TYPE_INT
, 0,0,0, NULL
},
113 {"complexity", &divx4_param
.complexity_modulation
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
114 {"readlog", &divx4_param
.log_file_read
, CONF_TYPE_STRING
, 0,0,1, NULL
},
115 {"writelog", &divx4_param
.log_file_write
, CONF_TYPE_STRING
, 0,0,1, NULL
},
116 {"mv_file", &divx4_param
.mv_file
, CONF_TYPE_STRING
, 0,0,1, NULL
},
117 {"data_partitioning", &divx4_param
.data_partitioning
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
118 {"qpel", &divx4_param
.quarter_pel
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
119 {"gmc", &divx4_param
.use_gmc
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
120 {"pv", &divx4_param
.psychovisual
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
121 {"pv_strength_frame", &divx4_param
.pv_strength_frame
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
122 {"pv_strength_MB", &divx4_param
.pv_strength_MB
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
123 {"interlace_mode", &divx4_param
.interlace_mode
, CONF_TYPE_INT
, CONF_RANGE
,0,3, NULL
},
124 {"crop", &divx4_param
.enable_crop
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
125 {"resize", &divx4_param
.enable_resize
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
126 {"width", &divx4_param
.resize_width
, CONF_TYPE_INT
, 0,0,0, NULL
},
127 {"height", &divx4_param
.resize_height
, CONF_TYPE_INT
, 0,0,0, NULL
},
128 {"left", &divx4_param
.crop_left
, CONF_TYPE_INT
, 0,0,0, NULL
},
129 {"right", &divx4_param
.crop_right
, CONF_TYPE_INT
, 0,0,0, NULL
},
130 {"top", &divx4_param
.crop_top
, CONF_TYPE_INT
, 0,0,0, NULL
},
131 {"bottom", &divx4_param
.crop_bottom
, CONF_TYPE_INT
, 0,0,0, NULL
},
132 {"resize_mode", &divx4_param
.resize_mode
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
133 {"temporal", &divx4_param
.temporal_enable
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
134 {"spatial", &divx4_param
.spatial_passes
, CONF_TYPE_INT
, CONF_RANGE
,0,3, NULL
},
135 {"temporal_level", &divx4_param
.temporal_level
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
136 {"spatial_level", &divx4_param
.spatial_level
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
138 {"bidirect", &divx4_param
.extensions
.use_bidirect
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
139 {"obmc", &divx4_param
.extensions
.obmc
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
140 {"data_partitioning", &divx4_param
.extensions
.data_partitioning
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
141 // {"mpeg2", &divx4_param.extensions.mpeg2_quant, CONF_TYPE_FLAG, 0,0,1, NULL},
142 {"qpel", &divx4_param
.extensions
.quarter_pel
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
143 {"intra_frame_threshold", &divx4_param
.extensions
.intra_frame_threshold
, CONF_TYPE_INT
, CONF_RANGE
,1,100, NULL
},
144 {"psychovisual", &divx4_param
.extensions
.psychovisual
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
145 {"pv", &divx4_param
.extensions
.psychovisual
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
146 {"pv_strength_frame", &divx4_param
.extensions
.pv_strength_frame
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
147 {"pv_strength_MB", &divx4_param
.extensions
.pv_strength_MB
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
148 {"testing_param", &divx4_param
.extensions
.testing_param
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
149 {"gmc", &divx4_param
.extensions
.use_gmc
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
150 {"interlace_mode", &divx4_param
.extensions
.interlace_mode
, CONF_TYPE_INT
, CONF_RANGE
,0,2, NULL
},
151 {"crop", &divx4_param
.extensions
.enable_crop
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
152 {"resize", &divx4_param
.extensions
.enable_resize
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
153 {"width", &divx4_param
.extensions
.resize_width
, CONF_TYPE_INT
, 0,0,0, NULL
},
154 {"height", &divx4_param
.extensions
.resize_height
, CONF_TYPE_INT
, 0,0,0, NULL
},
155 {"left", &divx4_param
.extensions
.crop_left
, CONF_TYPE_INT
, 0,0,0, NULL
},
156 {"right", &divx4_param
.extensions
.crop_right
, CONF_TYPE_INT
, 0,0,0, NULL
},
157 {"top", &divx4_param
.extensions
.crop_top
, CONF_TYPE_INT
, 0,0,0, NULL
},
158 {"bottom", &divx4_param
.extensions
.crop_bottom
, CONF_TYPE_INT
, 0,0,0, NULL
},
159 {"resize_mode", &divx4_param
.extensions
.resize_mode
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
160 {"temporal", &divx4_param
.extensions
.temporal_enable
, CONF_TYPE_FLAG
, 0,0,1, NULL
},
161 {"spatial", &divx4_param
.extensions
.spatial_passes
, CONF_TYPE_INT
, CONF_RANGE
,0,3, NULL
},
162 {"temporal_level", &divx4_param
.extensions
.temporal_level
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
163 {"spatial_level", &divx4_param
.extensions
.spatial_level
, CONF_TYPE_FLOAT
, CONF_RANGE
,0.0,1.0, NULL
},
164 {"mv_file", &divx4_param
.extensions
.mv_file
, CONF_TYPE_STRING
, 0,0,1, NULL
},
168 {"vbrpass", &vbrpass
, CONF_TYPE_INT
, CONF_RANGE
, 0, 2, NULL
},
169 {"vbrdebug", &vbrdebug
, CONF_TYPE_INT
, CONF_RANGE
, 0, 1, NULL
},
171 {"help", "TODO: divx4opts help!\n", CONF_TYPE_PRINT
, CONF_NOCFG
, 0, 0, NULL
},
172 {NULL
, NULL
, 0, 0, 0, 0, NULL
}
177 ENC_RESULT enc_result
;
181 vbr_control_t vbr_state
;
185 #define mux_v (vf->priv->mux)
187 static int config(struct vf_instance_s
* vf
,
188 int width
, int height
, int d_width
, int d_height
,
189 unsigned int flags
, unsigned int outfmt
){
191 #if ENCORE_MAJOR_VERSION >= 5200
192 DivXBitmapInfoHeader format
;
193 char profile
= (char) encore(0, ENC_OPT_PROFILE
, 0, 0);
195 mp_msg(MSGT_MENCODER
, MSGL_INFO
, "encoder binary profile: %c\n", profile
);
197 if((pass
<= 1 && (divx4_param
.vbr_mode
== RCMODE_VBV_MULTIPASS_NTH
||
198 divx4_param
.vbr_mode
== RCMODE_502_2PASS_2ND
)) ||
199 (pass
== 2 && (divx4_param
.vbr_mode
== RCMODE_VBV_1PASS
||
200 divx4_param
.vbr_mode
== RCMODE_1PASS_CONSTANT_Q
||
201 divx4_param
.vbr_mode
== RCMODE_VBV_MULTIPASS_1ST
||
202 divx4_param
.vbr_mode
== RCMODE_502_1PASS
||
203 divx4_param
.vbr_mode
== RCMODE_502_2PASS_1ST
||
204 divx4_param
.vbr_mode
== RCMODE_IMAGE_COMPRESS
))) {
205 mp_msg(MSGT_MENCODER
, MSGL_ERR
, "pass (%i) and rate control mode (%i) doesn't match, please consult encore2.h\n",
206 pass
, divx4_param
.vbr_mode
);
211 mux_v
->bih
->biWidth
=width
;
212 mux_v
->bih
->biHeight
=height
;
213 mux_v
->bih
->biSizeImage
=width
*height
*3;
214 mux_v
->aspect
= (float)d_width
/d_height
;
216 if(!divx4_param
.bitrate
) divx4_param
.bitrate
=800000;
217 else if(divx4_param
.bitrate
<=16000) divx4_param
.bitrate
*=1000;
218 if(!divx4_param
.quality
) divx4_param
.quality
=5; // the quality of compression ( 1 - fastest, 5 - best )
220 #if ENCORE_MAJOR_VERSION >= 5200
221 format
.biSize
=sizeof(DivXBitmapInfoHeader
);
222 format
.biWidth
=width
;
223 format
.biHeight
=height
;
224 format
.biSizeImage
=mux_v
->bih
->biSizeImage
;
225 if(divx4_param
.vbv_bitrate
> 0) {
226 divx4_param
.vbv_bitrate
= ((divx4_param
.vbv_bitrate
- 1) / 400 + 1) * 400;
227 divx4_param
.vbv_size
= ((divx4_param
.vbv_size
- 1) / 16384 + 1) * 16384;
228 divx4_param
.vbv_occupancy
= ((divx4_param
.vbv_occupancy
- 1) / 64 + 1) * 64;
231 divx4_param
.x_dim
=width
;
232 divx4_param
.y_dim
=height
;
233 divx4_param
.framerate
=(float)mux_v
->h
.dwRate
/mux_v
->h
.dwScale
;
234 // set some usefull defaults:
235 if(!divx4_param
.min_quantizer
) divx4_param
.min_quantizer
=2;
236 if(!divx4_param
.max_quantizer
) divx4_param
.max_quantizer
=31;
237 if(!divx4_param
.rc_period
) divx4_param
.rc_period
=2000;
238 if(!divx4_param
.rc_reaction_period
) divx4_param
.rc_reaction_period
=10;
239 if(!divx4_param
.rc_reaction_ratio
) divx4_param
.rc_reaction_ratio
=20;
244 vbrSetDefaults(&vf
->priv
->vbr_state
);
245 vf
->priv
->vbr_state
.desired_bitrate
= divx4_param
.bitrate
;
248 vf
->priv
->vbr_state
.mode
= VBR_MODE_1PASS
;
251 vf
->priv
->vbr_state
.mode
= VBR_MODE_2PASS_1
;
254 vf
->priv
->vbr_state
.mode
= VBR_MODE_2PASS_2
;
259 vf
->priv
->vbr_state
.debug
= vbrdebug
;
260 if (vbrInit(&vf
->priv
->vbr_state
) == -1)
262 /* XXX - kludge to workaround some DivX encoder limitations */
263 if (vf
->priv
->vbr_state
.mode
!= VBR_MODE_2PASS_2
)
264 divx4_param
.min_quantizer
= divx4_param
.max_quantizer
= vbrGetQuant(&vf
->priv
->vbr_state
);
268 #if ENCORE_MAJOR_VERSION >= 5200
271 format
.biCompression
=mmioFOURCC('Y','V','1','2');
275 format
.biCompression
=mmioFOURCC('I','Y','U','V');
279 format
.biCompression
=mmioFOURCC('I','4','2','0');
283 format
.biCompression
=mmioFOURCC('Y','U','Y','2');
287 format
.biCompression
=mmioFOURCC('V','4','2','2');
291 format
.biCompression
=mmioFOURCC('U','Y','V','Y');
295 format
.biCompression
=mmioFOURCC('Y','V','Y','U');
299 format
.biCompression
=0;
300 format
.biBitCount
=24;
304 format
.biCompression
=0;
305 format
.biBitCount
=32;
309 mp_msg(MSGT_MENCODER
,MSGL_ERR
,"divx4: unsupported picture format (%s)!\n",
310 vo_format_name(outfmt
));
314 encore(&vf
->priv
->enc_handle
, ENC_OPT_INIT
, &format
, &divx4_param
);
316 divx4_param
.handle
=NULL
;
317 encore(NULL
,ENC_OPT_INIT
,&divx4_param
,NULL
);
318 vf
->priv
->enc_handle
=divx4_param
.handle
;
320 case IMGFMT_YV12
: vf
->priv
->enc_frame
.colorspace
=ENC_CSP_YV12
; break;
322 case IMGFMT_I420
: vf
->priv
->enc_frame
.colorspace
=ENC_CSP_I420
; break;
323 case IMGFMT_YUY2
: vf
->priv
->enc_frame
.colorspace
=ENC_CSP_YUY2
; break;
324 case IMGFMT_UYVY
: vf
->priv
->enc_frame
.colorspace
=ENC_CSP_UYVY
; break;
327 vf
->priv
->enc_frame
.colorspace
=ENC_CSP_RGB24
; break;
329 mp_msg(MSGT_MENCODER
,MSGL_ERR
,"divx4: unsupported picture format (%s)!\n",
330 vo_format_name(outfmt
));
336 if (VbrControl_init_2pass_vbr_analysis(passtmpfile
, divx4_param
.quality
) == -1){
337 mp_msg(MSGT_MENCODER
,MSGL_ERR
,"2pass failed: filename=%s\n", passtmpfile
);
342 if (VbrControl_init_2pass_vbr_encoding(passtmpfile
,
344 divx4_param
.framerate
,
346 divx4_param
.quality
) == -1){
347 mp_msg(MSGT_MENCODER
,MSGL_ERR
,"2pass failed: filename=%s\n", passtmpfile
);
358 static void uninit(struct vf_instance_s
* vf
){
359 if (vbrpass
>= 0 && vbrFinish(&vf
->priv
->vbr_state
) == -1)
363 static void uninit(struct vf_instance_s
* vf
){
364 encore(vf
->priv
->enc_handle
, ENC_OPT_RELEASE
, 0, 0);
365 vf
->priv
->enc_handle
= NULL
;
369 static int control(struct vf_instance_s
* vf
, int request
, void* data
){
371 return CONTROL_UNKNOWN
;
374 static int query_format(struct vf_instance_s
* vf
, unsigned int fmt
){
379 return 3; // no conversion
382 return 1; // conversion
385 return 1 | VFCAP_FLIPPED
; // conversion+flipped
390 static int put_image(struct vf_instance_s
* vf
, mp_image_t
*mpi
){
391 ENC_RESULT enc_result
;
392 vf
->priv
->enc_frame
.image
=mpi
->planes
[0];
393 vf
->priv
->enc_frame
.bitstream
=mux_v
->buffer
;
394 vf
->priv
->enc_frame
.length
=mux_v
->buffer_size
;
395 #if ENCORE_MAJOR_VERSION >= 5200
396 vf
->priv
->enc_frame
.produce_empty_frame
= 0;
397 encore(vf
->priv
->enc_handle
, ENC_OPT_ENCODE
, &vf
->priv
->enc_frame
, &enc_result
);
398 if(enc_result
.cType
== 'I')
399 muxer_write_chunk(mux_v
,vf
->priv
->enc_frame
.length
,0x10);
401 muxer_write_chunk(mux_v
,vf
->priv
->enc_frame
.length
,0);
403 vf
->priv
->enc_frame
.mvs
=NULL
;
406 int quant
= vbrGetQuant(&vf
->priv
->vbr_state
);
407 int intra
= vbrGetIntra(&vf
->priv
->vbr_state
);
408 vf
->priv
->enc_frame
.quant
= quant
? quant
: 1;
409 vf
->priv
->enc_frame
.intra
= intra
;
410 /* XXX - kludge to workaround some DivX encoder limitations:
411 only pass 2 needs to call encore with VBR, and then it does
412 not report quantizer and intra*/
413 if (vf
->priv
->vbr_state
.mode
!= VBR_MODE_2PASS_2
)
414 encore(vf
->priv
->enc_handle
, ENC_OPT_ENCODE
, &vf
->priv
->enc_frame
, &enc_result
);
416 encore(vf
->priv
->enc_handle
, ENC_OPT_ENCODE_VBR
, &vf
->priv
->enc_frame
, &enc_result
);
417 enc_result
.quantizer
= quant
;
419 enc_result
.is_key_frame
= intra
;
421 if (vbrUpdate(&vf
->priv
->vbr_state
, enc_result
.quantizer
, enc_result
.is_key_frame
,
422 (enc_result
.total_bits
- enc_result
.texture_bits
) / 8, enc_result
.total_bits
/ 8,
428 if(pass
==2){ // handle 2-pass:
429 vf
->priv
->enc_frame
.quant
= VbrControl_get_quant();
430 vf
->priv
->enc_frame
.intra
= VbrControl_get_intra();
431 encore(vf
->priv
->enc_handle
,ENC_OPT_ENCODE_VBR
,&vf
->priv
->enc_frame
,&enc_result
);
432 VbrControl_update_2pass_vbr_encoding(enc_result
.motion_bits
,
433 enc_result
.texture_bits
,
434 enc_result
.total_bits
);
436 vf
->priv
->enc_frame
.quant
=0;
437 vf
->priv
->enc_frame
.intra
=0;
438 encore(vf
->priv
->enc_handle
,ENC_OPT_ENCODE
,&vf
->priv
->enc_frame
,&enc_result
);
440 VbrControl_update_2pass_vbr_analysis(enc_result
.is_key_frame
,
441 enc_result
.motion_bits
,
442 enc_result
.texture_bits
,
443 enc_result
.total_bits
,
444 enc_result
.quantizer
);
447 muxer_write_chunk(mux_v
,vf
->priv
->enc_frame
.length
,enc_result
.is_key_frame
?0x10:0);
452 //===========================================================================//
454 static int vf_open(vf_instance_t
*vf
, char* args
){
457 vf
->query_format
=query_format
;
458 vf
->put_image
=put_image
;
459 //#ifdef HAVE_XVID_VBR
462 vf
->priv
=malloc(sizeof(struct vf_priv_s
));
463 memset(vf
->priv
,0,sizeof(struct vf_priv_s
));
464 vf
->priv
->mux
=(muxer_stream_t
*)args
;
466 mux_v
->bih
=malloc(sizeof(BITMAPINFOHEADER
));
467 mux_v
->bih
->biSize
=sizeof(BITMAPINFOHEADER
);
468 mux_v
->bih
->biWidth
=0;
469 mux_v
->bih
->biHeight
=0;
470 mux_v
->bih
->biPlanes
=1;
471 mux_v
->bih
->biBitCount
=24;
472 #if ENCORE_MAJOR_VERSION >= 5010
473 mux_v
->bih
->biCompression
=mmioFOURCC('D','X','5','0');
475 mux_v
->bih
->biCompression
=mmioFOURCC('d','i','v','x');
481 vf_info_t ve_info_divx4
= {
485 "for internal use by mencoder",
489 //===========================================================================//