1 /*****************************************************************************
2 * x265.c: HEVC/H.265 video encoder
3 *****************************************************************************
4 * Copyright (C) 2013 Rafaël Carré
5 *
6 * Authors: Rafaël Carré <funman@videolanorg>
7 *
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.
12 *
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.
17 *
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 *****************************************************************************/
22
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
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>
34 #include <vlc_sout.h>
35 #include <vlc_codec.h>
36
37 #include <x265.h>
38
39 /*****************************************************************************
40 * Module descriptor
41 *****************************************************************************/
42 static int Open (vlc_object_t *);
43 static void Close(vlc_object_t *);
44
45 vlc_module_begin ()
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)
51 vlc_module_end ()
52
53 struct encoder_sys_t
54 {
55 x265_encoder *h;
56 x265_param param;
57
58 mtime_t i_initial_delay;
59
60 mtime_t dts;
61 mtime_t initial_date;
62 #ifndef NDEBUG
63 mtime_t start;
64 #endif
65 };
66
Encode(encoder_t * p_enc,picture_t * p_pict)67 static block_t *Encode(encoder_t *p_enc, picture_t *p_pict)
68 {
69 encoder_sys_t *p_sys = p_enc->p_sys;
70 x265_picture pic;
71
72 x265_picture_init(&p_sys->param, &pic);
73
74 if (likely(p_pict)) {
75 pic.pts = p_pict->date;
76 if (unlikely(p_sys->initial_date == 0)) {
77 p_sys->initial_date = p_pict->date;
78 #ifndef NDEBUG
79 p_sys->start = mdate();
80 #endif
81 }
82
83 for (int i = 0; i < p_pict->i_planes; i++) {
84 pic.planes[i] = p_pict->p[i].p_pixels;
85 pic.stride[i] = p_pict->p[i].i_pitch;
86 }
87 }
88
89 x265_nal *nal;
90 uint32_t i_nal = 0;
91 x265_encoder_encode(p_sys->h, &nal, &i_nal,
92 likely(p_pict) ? &pic : NULL, &pic);
93
94 if (!i_nal)
95 return NULL;
96
97 int i_out = 0;
98 for (uint32_t i = 0; i < i_nal; i++)
99 i_out += nal[i].sizeBytes;
100
101 block_t *p_block = block_Alloc(i_out);
102 if (!p_block)
103 return NULL;
104
105 /* all payloads are sequentially laid out in memory */
106 memcpy(p_block->p_buffer, nal[0].payload, i_out);
107
108 /* This isn't really valid for streams with B-frames */
109 p_block->i_length = CLOCK_FREQ *
110 p_enc->fmt_in.video.i_frame_rate_base /
111 p_enc->fmt_in.video.i_frame_rate;
112
113 p_block->i_pts = p_sys->initial_date + pic.poc * p_block->i_length;
114 p_block->i_dts = p_sys->initial_date + p_sys->dts++ * p_block->i_length;
115
116 switch (pic.sliceType)
117 {
118 case X265_TYPE_I:
119 case X265_TYPE_IDR:
120 p_block->i_flags |= BLOCK_FLAG_TYPE_I;
121 break;
122 case X265_TYPE_P:
123 p_block->i_flags |= BLOCK_FLAG_TYPE_P;
124 break;
125 case X265_TYPE_B:
126 case X265_TYPE_BREF:
127 p_block->i_flags |= BLOCK_FLAG_TYPE_B;
128 break;
129 }
130
131 #ifndef NDEBUG
132 msg_Dbg(p_enc, "%zu bytes (frame %"PRId64", %.2ffps)", p_block->i_buffer,
133 p_sys->dts, (float)p_sys->dts * CLOCK_FREQ / (mdate() - p_sys->start));
134 #endif
135
136 return p_block;
137 }
138
Open(vlc_object_t * p_this)139 static int Open (vlc_object_t *p_this)
140 {
141 encoder_t *p_enc = (encoder_t *)p_this;
142 encoder_sys_t *p_sys;
143
144 if (p_enc->fmt_out.i_codec != VLC_CODEC_HEVC && !p_enc->obj.force)
145 return VLC_EGENERIC;
146
147 p_enc->fmt_out.i_cat = VIDEO_ES;
148 p_enc->fmt_out.i_codec = VLC_CODEC_HEVC;
149 p_enc->p_sys = p_sys = malloc(sizeof(encoder_sys_t));
150 if (!p_sys)
151 return VLC_ENOMEM;
152
153 p_enc->fmt_in.i_codec = VLC_CODEC_I420;
154
155 x265_param *param = &p_sys->param;
156 x265_param_default(param);
157
158 param->frameNumThreads = vlc_GetCPUCount();
159 param->bEnableWavefront = 0; // buggy in x265, use frame threading for now
160 param->maxCUSize = 16; /* use smaller macroblock */
161
162 #if X265_BUILD >= 6
163 param->fpsNum = p_enc->fmt_in.video.i_frame_rate;
164 param->fpsDenom = p_enc->fmt_in.video.i_frame_rate_base;
165 if (!param->fpsNum) {
166 param->fpsNum = 25;
167 param->fpsDenom = 1;
168 }
169 #else
170 if (p_enc->fmt_in.video.i_frame_rate_base) {
171 param->frameRate = p_enc->fmt_in.video.i_frame_rate /
172 p_enc->fmt_in.video.i_frame_rate_base;
173 } else {
174 param->frameRate = 25;
175 }
176 #endif
177 param->sourceWidth = p_enc->fmt_in.video.i_visible_width;
178 param->sourceHeight = p_enc->fmt_in.video.i_visible_height;
179
180 if (param->sourceWidth & (param->maxCUSize - 1)) {
181 msg_Err(p_enc, "Width (%d) must be a multiple of %d",
182 param->sourceWidth, param->maxCUSize);
183 free(p_sys);
184 return VLC_EGENERIC;
185 }
186 if (param->sourceHeight & 7) {
187 msg_Err(p_enc, "Height (%d) must be a multiple of 8", param->sourceHeight);
188 free(p_sys);
189 return VLC_EGENERIC;
190 }
191
192 if (p_enc->fmt_out.i_bitrate > 0) {
193 param->rc.bitrate = p_enc->fmt_out.i_bitrate / 1000;
194 param->rc.rateControlMode = X265_RC_ABR;
195 }
196
197 p_sys->h = x265_encoder_open(param);
198 if (p_sys->h == NULL) {
199 msg_Err(p_enc, "cannot open x265 encoder");
200 free(p_sys);
201 return VLC_EGENERIC;
202 }
203
204 x265_nal *nal;
205 uint32_t i_nal;
206 if (x265_encoder_headers(p_sys->h, &nal, &i_nal) < 0) {
207 msg_Err(p_enc, "cannot get x265 headers");
208 Close(VLC_OBJECT(p_enc));
209 return VLC_EGENERIC;
210 }
211
212 size_t i_extra = 0;
213 for (uint32_t i = 0; i < i_nal; i++)
214 i_extra += nal[i].sizeBytes;
215
216 p_enc->fmt_out.i_extra = i_extra;
217
218 uint8_t *p_extra = p_enc->fmt_out.p_extra = malloc(i_extra);
219 if (!p_extra) {
220 Close(VLC_OBJECT(p_enc));
221 return VLC_ENOMEM;
222 }
223
224 for (uint32_t i = 0; i < i_nal; i++) {
225 memcpy(p_extra, nal[i].payload, nal[i].sizeBytes);
226 p_extra += nal[i].sizeBytes;
227 }
228
229 p_sys->dts = 0;
230 p_sys->initial_date = 0;
231 p_sys->i_initial_delay = 0;
232
233 p_enc->pf_encode_video = Encode;
234 p_enc->pf_encode_audio = NULL;
235
236 return VLC_SUCCESS;
237 }
238
Close(vlc_object_t * p_this)239 static void Close(vlc_object_t *p_this)
240 {
241 encoder_t *p_enc = (encoder_t *)p_this;
242 encoder_sys_t *p_sys = p_enc->p_sys;
243
244 x265_encoder_close(p_sys->h);
245
246 free(p_sys);
247 }
248