1 /*****************************************************************************
3 * - H.264 encoder for mencoder using x264 -
5 * Copyright (C) 2004 LINUX4MEDIA GmbH
6 * Copyright (C) 2004 Ark Linux
8 * Written by Bernhard Rosenkraenzer <bero@arklinux.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation, or if, and only if,
13 * version 2 is ruled invalid in a court of law, any later version
14 * of the GNU General Public License published by the Free Software
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 *****************************************************************************/
37 #include "codec-cfg.h"
38 #include "stream/stream.h"
39 #include "libmpdemux/demuxer.h"
40 #include "libmpdemux/stheader.h"
42 #include "stream/stream.h"
43 #include "libmpdemux/muxer.h"
45 #include "img_format.h"
51 typedef struct _h264_module_t
{
57 extern char* passtmpfile
;
59 static x264_param_t param
;
60 static int parse_error
= 0;
62 static int encode_nals(uint8_t *buf
, int size
, x264_nal_t
*nals
, int nnal
){
66 for(i
= 0; i
< nnal
; i
++){
67 int s
= x264_nal_encode(p
, &size
, 1, nals
+ i
);
76 static int put_image(struct vf_instance_s
*vf
, mp_image_t
*mpi
, double pts
);
77 static int encode_frame(struct vf_instance_s
*vf
, x264_picture_t
*pic_in
);
79 void x264enc_set_param(const m_option_t
* opt
, char* arg
)
81 static int initted
= 0;
83 x264_param_default(¶m
);
84 x264_param_parse(¶m
, "psnr", "no");
85 x264_param_parse(¶m
, "ssim", "no");
99 arg
+= strcspn(arg
, ":");
105 value
= strchr( name
, '=' );
111 if(!strcmp(name
, "turbo")) {
112 turbo
= value
? atoi(value
) : 1;
116 ret
= x264_param_parse(¶m
, name
, value
);
117 if(ret
== X264_PARAM_BAD_NAME
)
118 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option x264encopts: Unknown suboption %s\n", name
);
119 if(ret
== X264_PARAM_BAD_VALUE
)
120 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option x264encopts: Bad argument %s=%s\n", name
, value
? value
: "(null)");
122 /* mark this option as done, so it's not reparsed if there's another -x264encopts */
128 if(param
.rc
.b_stat_write
&& !param
.rc
.b_stat_read
) {
129 /* Adjust or disable some flags to gain speed in the first pass */
132 param
.i_frame_reference
= ( param
.i_frame_reference
+ 1 ) >> 1;
133 param
.analyse
.i_subpel_refine
= FFMAX( FFMIN( 3, param
.analyse
.i_subpel_refine
- 1 ), 1 );
134 param
.analyse
.inter
&= ( ~X264_ANALYSE_PSUB8x8
);
135 param
.analyse
.inter
&= ( ~X264_ANALYSE_BSUB16x16
);
136 param
.analyse
.i_trellis
= 0;
140 param
.i_frame_reference
= 1;
141 param
.analyse
.i_subpel_refine
= 1;
142 param
.analyse
.i_me_method
= X264_ME_DIA
;
143 param
.analyse
.inter
= 0;
144 param
.analyse
.b_transform_8x8
= 0;
145 param
.analyse
.b_weighted_bipred
= 0;
146 param
.analyse
.i_trellis
= 0;
151 static int config(struct vf_instance_s
* vf
, int width
, int height
, int d_width
, int d_height
, unsigned int flags
, unsigned int outfmt
) {
152 h264_module_t
*mod
=(h264_module_t
*)vf
->priv
;
157 mod
->mux
->bih
->biWidth
= width
;
158 mod
->mux
->bih
->biHeight
= height
;
159 mod
->mux
->aspect
= (float)d_width
/d_height
;
161 // make sure param is initialized
162 x264enc_set_param(NULL
, "");
163 param
.i_width
= width
;
164 param
.i_height
= height
;
165 param
.i_fps_num
= mod
->mux
->h
.dwRate
;
166 param
.i_fps_den
= mod
->mux
->h
.dwScale
;
167 param
.vui
.i_sar_width
= d_width
*height
;
168 param
.vui
.i_sar_height
= d_height
*width
;
170 x264_param_parse(¶m
, "stats", passtmpfile
);
174 param
.i_csp
= X264_CSP_I420
;
175 mod
->mux
->bih
->biSizeImage
= width
* height
* 3;
178 param
.i_csp
= X264_CSP_YV12
;
179 mod
->mux
->bih
->biSizeImage
= width
* height
* 3;
182 param
.i_csp
= X264_CSP_I422
;
183 mod
->mux
->bih
->biSizeImage
= width
* height
* 3;
186 param
.i_csp
= X264_CSP_I444
;
187 mod
->mux
->bih
->biSizeImage
= width
* height
* 3;
190 param
.i_csp
= X264_CSP_YUYV
;
191 mod
->mux
->bih
->biSizeImage
= width
* height
* 3;
194 param
.i_csp
= X264_CSP_RGB
;
195 mod
->mux
->bih
->biSizeImage
= width
* height
* 3;
198 param
.i_csp
= X264_CSP_BGR
;
199 mod
->mux
->bih
->biSizeImage
= width
* height
* 3;
202 param
.i_csp
= X264_CSP_BGRA
;
203 mod
->mux
->bih
->biSizeImage
= width
* height
* 4;
206 mp_msg(MSGT_MENCODER
, MSGL_ERR
, "Wrong colorspace.\n");
210 mod
->x264
= x264_encoder_open(¶m
);
212 mp_msg(MSGT_MENCODER
, MSGL_ERR
, "x264_encoder_open failed.\n");
216 if(!param
.b_repeat_headers
){
219 int extradata_size
, nnal
, i
, s
= 0;
221 x264_encoder_headers(mod
->x264
, &nal
, &nnal
);
223 /* 5 bytes NAL header + worst case escaping */
224 for(i
= 0; i
< nnal
; i
++)
225 s
+= 5 + nal
[i
].i_payload
* 4 / 3;
227 extradata
= malloc(s
);
228 extradata_size
= encode_nals(extradata
, s
, nal
, nnal
);
230 mod
->mux
->bih
= realloc(mod
->mux
->bih
, sizeof(BITMAPINFOHEADER
) + extradata_size
);
231 memcpy(mod
->mux
->bih
+ 1, extradata
, extradata_size
);
232 mod
->mux
->bih
->biSize
= sizeof(BITMAPINFOHEADER
) + extradata_size
;
235 if (param
.i_bframe
> 1 && param
.b_bframe_pyramid
)
236 mod
->mux
->decoder_delay
= 2;
238 mod
->mux
->decoder_delay
= param
.i_bframe
? 1 : 0;
243 static int control(struct vf_instance_s
* vf
, int request
, void *data
)
245 h264_module_t
*mod
=(h264_module_t
*)vf
->priv
;
247 case VFCTRL_FLUSH_FRAMES
:
249 while(encode_frame(vf
, NULL
) > 0);
252 return CONTROL_UNKNOWN
;
256 static int query_format(struct vf_instance_s
* vf
, unsigned int fmt
)
260 return (VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
);
268 /* These colorspaces are supported, but they'll just have
269 * to be converted to I420 internally */
270 return 0; /* VFCAP_CSP_SUPPORTED */
275 static int put_image(struct vf_instance_s
*vf
, mp_image_t
*mpi
, double pts
)
277 h264_module_t
*mod
=(h264_module_t
*)vf
->priv
;
280 memset(&mod
->pic
, 0, sizeof(x264_picture_t
));
281 mod
->pic
.img
.i_csp
=param
.i_csp
;
282 mod
->pic
.img
.i_plane
=3;
284 mod
->pic
.img
.plane
[i
] = mpi
->planes
[i
];
285 mod
->pic
.img
.i_stride
[i
] = mpi
->stride
[i
];
288 mod
->pic
.i_type
= X264_TYPE_AUTO
;
290 return encode_frame(vf
, &mod
->pic
) >= 0;
293 static int encode_frame(struct vf_instance_s
*vf
, x264_picture_t
*pic_in
)
295 h264_module_t
*mod
=(h264_module_t
*)vf
->priv
;
296 x264_picture_t pic_out
;
302 if(x264_encoder_encode(mod
->x264
, &nal
, &i_nal
, pic_in
, &pic_out
) < 0) {
303 mp_msg(MSGT_MENCODER
, MSGL_ERR
, "x264_encoder_encode failed\n");
307 for(i
=0; i
< i_nal
; i
++) {
308 int i_data
= mod
->mux
->buffer_size
- i_size
;
309 i_size
+= x264_nal_encode(mod
->mux
->buffer
+ i_size
, &i_data
, 1, &nal
[i
]);
312 int keyframe
= (pic_out
.i_type
== X264_TYPE_IDR
) ||
313 (pic_out
.i_type
== X264_TYPE_I
314 && param
.i_frame_reference
== 1
316 muxer_write_chunk(mod
->mux
, i_size
, keyframe
?0x10:0, MP_NOPTS_VALUE
, MP_NOPTS_VALUE
);
319 ++mod
->mux
->encoder_delay
;
324 static void uninit(struct vf_instance_s
*vf
)
326 h264_module_t
*mod
=(h264_module_t
*)vf
->priv
;
328 x264_encoder_close(mod
->x264
);
331 static int vf_open(vf_instance_t
*vf
, char *args
) {
335 vf
->default_caps
= VFCAP_CONSTANT
;
336 vf
->control
= control
;
337 vf
->query_format
= query_format
;
338 vf
->put_image
= put_image
;
340 vf
->priv
= malloc(sizeof(h264_module_t
));
342 mod
=(h264_module_t
*)vf
->priv
;
343 mod
->mux
= (muxer_stream_t
*)args
;
344 mod
->mux
->bih
= malloc(sizeof(BITMAPINFOHEADER
));
345 memset(mod
->mux
->bih
, 0, sizeof(BITMAPINFOHEADER
));
346 mod
->mux
->bih
->biSize
= sizeof(BITMAPINFOHEADER
);
347 mod
->mux
->bih
->biPlanes
= 1;
348 mod
->mux
->bih
->biBitCount
= 24;
349 mod
->mux
->bih
->biCompression
= mmioFOURCC('h', '2', '6', '4');
354 vf_info_t ve_info_x264
= {
357 "Bernhard Rosenkraenzer <bero@arklinux.org>",
358 "(C) 2004 LINUX4MEDIA GmbH; (C) 2004 Ark Linux",