1 /*****************************************************************************
2 * x265.c: HEVC/H.265 video encoder
3 *****************************************************************************
4 * Copyright (C) 2013 Rafaël Carré
6 * Authors: Rafaël Carré <funman@videolanorg>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_threads.h>
35 #include <vlc_codec.h>
39 /*****************************************************************************
41 *****************************************************************************/
42 static int Open (vlc_object_t
*);
43 static void Close(vlc_object_t
*);
46 set_description(N_("H.265/HEVC encoder (x265)"))
47 set_capability("encoder", 200)
48 set_callbacks(Open
, Close
)
49 set_category(CAT_INPUT
)
50 set_subcategory(SUBCAT_INPUT_VCODEC
)
59 vlc_tick_t initial_date
;
65 static block_t
*Encode(encoder_t
*p_enc
, picture_t
*p_pict
)
67 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
70 x265_picture_init(&p_sys
->param
, &pic
);
73 pic
.pts
= p_pict
->date
;
74 if (unlikely(p_sys
->initial_date
== VLC_TICK_INVALID
)) {
75 p_sys
->initial_date
= p_pict
->date
;
77 p_sys
->start
= vlc_tick_now();
81 for (int i
= 0; i
< p_pict
->i_planes
; i
++) {
82 pic
.planes
[i
] = p_pict
->p
[i
].p_pixels
;
83 pic
.stride
[i
] = p_pict
->p
[i
].i_pitch
;
89 x265_encoder_encode(p_sys
->h
, &nal
, &i_nal
,
90 likely(p_pict
) ? &pic
: NULL
, &pic
);
96 for (uint32_t i
= 0; i
< i_nal
; i
++)
97 i_out
+= nal
[i
].sizeBytes
;
99 block_t
*p_block
= block_Alloc(i_out
);
103 /* all payloads are sequentially laid out in memory */
104 memcpy(p_block
->p_buffer
, nal
[0].payload
, i_out
);
106 /* This isn't really valid for streams with B-frames */
107 p_block
->i_length
= vlc_tick_from_samples(
108 p_enc
->fmt_in
.video
.i_frame_rate_base
,
109 p_enc
->fmt_in
.video
.i_frame_rate
);
111 p_block
->i_pts
= p_sys
->initial_date
+ pic
.poc
* p_block
->i_length
;
112 p_block
->i_dts
= p_sys
->initial_date
+ p_sys
->frame_count
++ * p_block
->i_length
;
114 switch (pic
.sliceType
)
118 p_block
->i_flags
|= BLOCK_FLAG_TYPE_I
;
121 p_block
->i_flags
|= BLOCK_FLAG_TYPE_P
;
125 p_block
->i_flags
|= BLOCK_FLAG_TYPE_B
;
130 msg_Dbg(p_enc
, "%zu bytes (frame %u, %.2ffps)", p_block
->i_buffer
,
131 p_sys
->frame_count
, (float)p_sys
->frame_count
* CLOCK_FREQ
/ (vlc_tick_now() - p_sys
->start
));
137 static int Open (vlc_object_t
*p_this
)
139 encoder_t
*p_enc
= (encoder_t
*)p_this
;
140 encoder_sys_t
*p_sys
;
142 if (p_enc
->fmt_out
.i_codec
!= VLC_CODEC_HEVC
&& !p_enc
->obj
.force
)
145 p_enc
->fmt_out
.i_cat
= VIDEO_ES
;
146 p_enc
->fmt_out
.i_codec
= VLC_CODEC_HEVC
;
147 p_enc
->p_sys
= p_sys
= malloc(sizeof(encoder_sys_t
));
151 p_enc
->fmt_in
.i_codec
= VLC_CODEC_I420
;
153 x265_param
*param
= &p_sys
->param
;
154 x265_param_default(param
);
156 param
->frameNumThreads
= vlc_GetCPUCount();
157 param
->bEnableWavefront
= 0; // buggy in x265, use frame threading for now
158 param
->maxCUSize
= 16; /* use smaller macroblock */
161 param
->fpsNum
= p_enc
->fmt_in
.video
.i_frame_rate
;
162 param
->fpsDenom
= p_enc
->fmt_in
.video
.i_frame_rate_base
;
163 if (!param
->fpsNum
) {
168 if (p_enc
->fmt_in
.video
.i_frame_rate_base
) {
169 param
->frameRate
= p_enc
->fmt_in
.video
.i_frame_rate
/
170 p_enc
->fmt_in
.video
.i_frame_rate_base
;
172 param
->frameRate
= 25;
175 param
->sourceWidth
= p_enc
->fmt_in
.video
.i_visible_width
;
176 param
->sourceHeight
= p_enc
->fmt_in
.video
.i_visible_height
;
178 if (param
->sourceWidth
& (param
->maxCUSize
- 1)) {
179 msg_Err(p_enc
, "Width (%d) must be a multiple of %d",
180 param
->sourceWidth
, param
->maxCUSize
);
184 if (param
->sourceHeight
& 7) {
185 msg_Err(p_enc
, "Height (%d) must be a multiple of 8", param
->sourceHeight
);
190 if (p_enc
->fmt_out
.i_bitrate
> 0) {
191 param
->rc
.bitrate
= p_enc
->fmt_out
.i_bitrate
/ 1000;
192 param
->rc
.rateControlMode
= X265_RC_ABR
;
195 p_sys
->h
= x265_encoder_open(param
);
196 if (p_sys
->h
== NULL
) {
197 msg_Err(p_enc
, "cannot open x265 encoder");
204 if (x265_encoder_headers(p_sys
->h
, &nal
, &i_nal
) < 0) {
205 msg_Err(p_enc
, "cannot get x265 headers");
206 Close(VLC_OBJECT(p_enc
));
211 for (uint32_t i
= 0; i
< i_nal
; i
++)
212 i_extra
+= nal
[i
].sizeBytes
;
214 p_enc
->fmt_out
.i_extra
= i_extra
;
216 uint8_t *p_extra
= p_enc
->fmt_out
.p_extra
= malloc(i_extra
);
218 Close(VLC_OBJECT(p_enc
));
222 for (uint32_t i
= 0; i
< i_nal
; i
++) {
223 memcpy(p_extra
, nal
[i
].payload
, nal
[i
].sizeBytes
);
224 p_extra
+= nal
[i
].sizeBytes
;
227 p_sys
->frame_count
= 0;
228 p_sys
->initial_date
= VLC_TICK_INVALID
;
230 p_enc
->pf_encode_video
= Encode
;
231 p_enc
->pf_encode_audio
= NULL
;
236 static void Close(vlc_object_t
*p_this
)
238 encoder_t
*p_enc
= (encoder_t
*)p_this
;
239 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
241 x265_encoder_close(p_sys
->h
);