]> git.sesse.net Git - vlc/blob - modules/codec/x265.c
x265 encoder
[vlc] / modules / codec / x265.c
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 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_threads.h>
33 #include <vlc_sout.h>
34 #include <vlc_codec.h>
35
36 #include <x265.h>
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41 static int  Open (vlc_object_t *);
42 static void Close(vlc_object_t *);
43
44 vlc_module_begin ()
45     set_description(N_("H.265/HEVC encoder (x265)"))
46     set_capability("encoder", 200)
47     set_callbacks(Open, Close)
48     set_category(CAT_INPUT)
49     set_subcategory(SUBCAT_INPUT_VCODEC)
50 vlc_module_end ()
51
52 struct encoder_sys_t
53 {
54     x265_t          *h;
55     x265_param_t    param;
56
57     bool            write_headers;
58
59     mtime_t         i_initial_delay;
60
61     mtime_t         dts;
62     mtime_t         initial_date;
63 #ifndef NDEBUG
64     mtime_t         start;
65 #endif
66 };
67
68 static block_t *Encode(encoder_t *p_enc, picture_t *p_pict)
69 {
70     encoder_sys_t *p_sys = p_enc->p_sys;
71     x265_picture_t pic;
72
73     if (likely(p_pict)) {
74         if (unlikely(p_sys->initial_date == 0)) {
75             p_sys->initial_date = p_pict->date;
76 #ifndef NDEBUG
77             p_sys->start = mdate();
78 #endif
79         }
80
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;
84         }
85     }
86
87     x265_nal_t *nal;
88     int i_nal = 0;
89     x265_encoder_encode(p_sys->h, &nal, &i_nal,
90             likely(p_pict) ? &pic : NULL, &pic);
91
92     if (!i_nal)
93         return NULL;
94
95     int i_out = 0;
96     for (int i = 0; i < i_nal; i++)
97         i_out += nal[i].i_payload;
98
99     int i_extra = 0;
100     if (unlikely(p_sys->write_headers)) {
101         i_extra = p_enc->fmt_out.i_extra;
102         p_sys->write_headers = false;
103     }
104
105     block_t *p_block = block_Alloc(i_extra + i_out);
106     if (!p_block)
107         return NULL;
108
109     if (unlikely(i_extra))
110        memcpy(p_block->p_buffer, p_enc->fmt_out.p_extra, i_extra);
111
112     /* all payloads are sequentially laid out in memory */
113     memcpy(p_block->p_buffer + i_extra, nal[0].p_payload, i_out);
114
115     /* This isn't really valid for streams with B-frames */
116     p_block->i_length = CLOCK_FREQ *
117         p_enc->fmt_in.video.i_frame_rate_base /
118             p_enc->fmt_in.video.i_frame_rate;
119
120     p_block->i_pts = p_sys->initial_date + pic.poc * p_block->i_length;
121     p_block->i_dts = p_sys->initial_date + p_sys->dts++ * p_block->i_length;
122
123 #ifndef NDEBUG
124     msg_Dbg(p_enc, "%zu bytes (frame %"PRId64", %.2ffps)", p_block->i_buffer,
125         p_sys->dts, (float)p_sys->dts * CLOCK_FREQ / (mdate() - p_sys->start));
126 #endif
127
128     return p_block;
129 }
130
131 static int  Open (vlc_object_t *p_this)
132 {
133     encoder_t     *p_enc = (encoder_t *)p_this;
134     encoder_sys_t *p_sys;
135
136     if (p_enc->fmt_out.i_codec != VLC_CODEC_HEVC && !p_enc->b_force)
137         return VLC_EGENERIC;
138
139     p_enc->fmt_out.i_cat = VIDEO_ES;
140     p_enc->fmt_out.i_codec = VLC_CODEC_HEVC;
141     p_enc->p_sys = p_sys = malloc(sizeof(encoder_sys_t));
142     if (!p_sys)
143         return VLC_ENOMEM;
144
145     p_enc->fmt_in.i_codec = VLC_CODEC_I420;
146
147     x265_param_t *param = &p_sys->param;
148     x265_param_default(param);
149
150     param->frameNumThreads = vlc_GetCPUCount();
151     param->bEnableWavefront = 0; // buggy in x265, use frame threading for now
152     param->maxCUSize = 16; /* use smaller macroblock */
153
154     param->frameRate = p_enc->fmt_in.video.i_frame_rate /
155             p_enc->fmt_in.video.i_frame_rate_base;
156     param->sourceWidth = p_enc->fmt_in.video.i_visible_width;
157     param->sourceHeight = p_enc->fmt_in.video.i_visible_height;
158
159     if (param->sourceWidth & (param->maxCUSize - 1)) {
160         msg_Err(p_enc, "Width (%d) must be a multiple of %d",
161             param->sourceWidth, param->maxCUSize);
162         free(p_sys);
163         return VLC_EGENERIC;
164     }
165     if (param->sourceHeight & 7) {
166         msg_Err(p_enc, "Height (%d) must be a multiple of 8", param->sourceHeight);
167         free(p_sys);
168         return VLC_EGENERIC;
169     }
170
171     if (p_enc->fmt_out.i_bitrate > 0) {
172         param->rc.bitrate = p_enc->fmt_out.i_bitrate / 1000;
173         param->rc.rateControlMode = X265_RC_ABR;
174     }
175
176     p_sys->h = x265_encoder_open(param);
177     if (p_sys->h == NULL) {
178         msg_Err(p_enc, "cannot open x265 encoder");
179         free(p_sys);
180         return VLC_EGENERIC;
181     }
182
183     x265_nal_t *nal;
184     int i_nal;
185     if (x265_encoder_headers(p_sys->h, &nal, &i_nal)) {
186         msg_Err(p_enc, "cannot get x265 headers");
187         Close(VLC_OBJECT(p_enc));
188         return VLC_EGENERIC;
189     }
190
191     size_t i_extra = 0;
192     for (int i = 0; i < i_nal; i++)
193         i_extra += nal[i].i_payload;
194
195     p_enc->fmt_out.i_extra = i_extra;
196
197     uint8_t *p_extra = p_enc->fmt_out.p_extra = malloc(i_extra);
198     if (!p_extra) {
199         Close(VLC_OBJECT(p_enc));
200         return VLC_ENOMEM;
201     }
202
203     for (int i = 0; i < i_nal; i++) {
204         memcpy(p_extra, nal[i].p_payload, nal[i].i_payload);
205         p_extra += nal[i].i_payload;
206     }
207
208     p_sys->dts = 0;
209     p_sys->initial_date = 0;
210     p_sys->i_initial_delay = 0;
211     p_sys->write_headers = true;
212
213     p_enc->pf_encode_video = Encode;
214     p_enc->pf_encode_audio = NULL;
215
216     return VLC_SUCCESS;
217 }
218
219 static void Close(vlc_object_t *p_this)
220 {
221     encoder_t     *p_enc = (encoder_t *)p_this;
222     encoder_sys_t *p_sys = p_enc->p_sys;
223
224     x265_encoder_close(p_sys->h, NULL);
225
226     free(p_sys);
227 }