1 /*
2 * H.264 Plugin codec for OpenH323/OPAL
3 *
4 * Copyright (C) 2007 Matthias Schneider, All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 */
21
22 #include "plugin-config.h"
23
24 #include "enc-ctx.h"
25
26 #ifdef _MSC_VER
27 #include "../../common/rtpframe.h"
28 #include "../../common/trace.h"
29 #else
30 #include "trace.h"
31 #include "rtpframe.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <math.h>
37 #if defined(_WIN32) || defined(_WIN32_WCE)
38 #include <malloc.h>
39 #define STRCMPI _strcmpi
40 #else
41 #include <semaphore.h>
42 #define STRCMPI strcasecmp
43 #endif
44 #include <string.h>
45
46 #ifndef X264_LINK_STATIC
47 X264Library X264Lib;
48 #endif
49
logCallbackX264(void *,int level,const char * fmt,va_list arg)50 static void logCallbackX264 (void * /*priv*/, int level, const char *fmt, va_list arg) {
51 const unsigned BUFSIZE = 2048;
52 char buffer[BUFSIZE];
53 int severity = 0;
54 switch (level) {
55 case X264_LOG_NONE: severity = 1; break;
56 case X264_LOG_ERROR: severity = 1; break;
57 case X264_LOG_WARNING: severity = 3; break;
58 case X264_LOG_INFO: severity = 4; break;
59 case X264_LOG_DEBUG: severity = 4; break;
60 default: severity = 4; break;
61 }
62 sprintf(buffer, "H264\tx264\t");
63 vsnprintf(buffer + strlen(buffer), BUFSIZE - strlen(buffer), fmt, arg);
64 if (strlen(buffer) > 0)
65 buffer[strlen(buffer)-1] = 0;
66 if (severity == 4)
67 { TRACE_UP (severity, buffer); }
68 else
69 { TRACE (severity, buffer); }
70 }
71
X264EncoderContext()72 X264EncoderContext::X264EncoderContext()
73 : _codec(NULL), _txH264Frame(NULL), _PFramesSinceLastIFrame(0),
74 _IFrameInterval(0), _frameCounter(0), _fastUpdateRequested(false)
75 {
76 Initialise();
77 }
78
~X264EncoderContext()79 X264EncoderContext::~X264EncoderContext()
80 {
81 Uninitialise();
82 }
83
Initialise()84 bool X264EncoderContext::Initialise()
85 {
86 Uninitialise();
87
88 _frameCounter = 0;
89 _PFramesSinceLastIFrame = 0;
90 _fastUpdateRequested = false;
91
92 _txH264Frame = new H264Frame();
93 _txH264Frame->SetMaxPayloadSize(H264_PAYLOAD_SIZE);
94
95 _inputFrame.i_type = X264_TYPE_AUTO;
96 _inputFrame.i_qpplus1 = 0;
97 _inputFrame.img.i_csp = X264_CSP_I420;
98
99 #if X264_BUILD > 101
100 _inputFrame.prop.quant_offsets = NULL;
101 _inputFrame.prop.quant_offsets_free = NULL;
102 #endif
103
104 X264_PARAM_DEFAULT(&_context);
105
106 // No multicore support
107 _context.i_threads = 1;
108 _context.b_sliced_threads = 1;
109 _context.b_deterministic = 1;
110 _context.i_sync_lookahead = 0;
111 _context.i_frame_reference = 1;
112 _context.i_bframe = 0;
113 _context.b_vfr_input = 0;
114 _context.rc.b_mb_tree = 0;
115
116 // No aspect ratio correction
117 _context.vui.i_sar_width = 0;
118 _context.vui.i_sar_height = 0;
119
120 #if X264_BUILD > 101
121 // No automatic keyframe generation
122 _context.i_keyint_max = 90; // X264_KEYINT_MAX_INFINITE;
123 _context.i_keyint_min = 15; // X264_KEYINT_MAX_INFINITE;
124 #endif
125
126 // Enable logging
127 _context.pf_log = logCallbackX264;
128 _context.i_log_level = X264_LOG_WARNING; //X264_LOG_DEBUG;
129 _context.p_log_private = NULL;
130
131 // Single NAL Mode
132 #if X264_BUILD > 79
133 _context.i_slice_max_size = H264_SINGLE_NAL_SIZE; // Default NAL Size
134 _context.b_repeat_headers = 1; // repeat SPS/PPS before each key frame
135 _context.b_annexb = 1; // place start codes (4 bytes) before NAL units
136 #endif
137
138 SetFrameWidth (CIF_WIDTH);
139 SetFrameHeight (CIF_HEIGHT);
140 SetFrameRate (H264_FRAME_RATE);
141 SetProfileLevel (H264_PROFILE_LEVEL);
142 SetTSTO (H264_TSTO); // TODO: is this really functional
143 SetMaxKeyFramePeriod(H264_KEY_FRAME_INTERVAL);
144
145 #ifdef H264_OPTIMAL_QUALITY
146 // Rate control set to CRF mode (ignoring bitrate restrictions)
147 _context.rc.i_rc_method = X264_RC_CRF;
148 _context.rc.f_rf_constant = 16.0; // great quality
149 #else
150 // Rate control set to ABR mode
151 #if 1
152 _context.rc.i_rc_method = X264_RC_ABR;
153 _context.rc.f_rate_tolerance = 1.0;
154 _context.rc.i_lookahead = 0;
155 _context.rc.i_qp_step = 6;
156 _context.rc.psz_stat_out = 0;
157 _context.rc.psz_stat_in = 0;
158 _context.rc.f_vbv_buffer_init = 0;
159 _context.i_scenecut_threshold = 0;
160 #else
161 _context.rc.i_rc_method = X264_RC_ABR;
162 _context.rc.i_qp_min = 25;
163 _context.rc.i_qp_max = 51;
164 _context.rc.i_qp_step = 6;
165 _context.rc.f_rate_tolerance = 1.0;
166 _context.rc.i_vbv_max_bitrate = 0;
167 _context.rc.psz_stat_out = 0;
168 _context.rc.psz_stat_in = 0;
169 _context.rc.f_vbv_buffer_init = 0;
170 _context.rc.i_vbv_buffer_size = 0;
171 _context.rc.i_lookahead = 0;
172 _context.i_scenecut_threshold = 0;
173 #endif
174 SetTargetBitrate ((unsigned)(H264_BITRATE / 1000));
175 #endif
176
177 // Analysis support
178 _context.analyse.intra = 3;
179 _context.analyse.inter = 0;
180 _context.analyse.b_transform_8x8 = 0;
181 _context.analyse.i_weighted_pred = 0;
182 _context.analyse.i_direct_mv_pred = 1;
183 _context.analyse.i_me_method = 0;
184 _context.analyse.i_me_range = 16;
185 _context.analyse.i_subpel_refine = 1;
186 _context.analyse.i_trellis = 0;
187 _context.analyse.b_psnr = 0;
188 _context.analyse.b_fast_pskip = 1;
189 _context.analyse.b_dct_decimate = 1;
190 _context.analyse.i_noise_reduction= 0;
191 _context.analyse.b_ssim = 0;
192
193 #ifndef X264_DELAYLOAD
194 _codec = X264_ENCODER_OPEN(&_context);
195 if (_codec == NULL) {
196 TRACE(1, "H264\tEncoder\tCouldn't init x264 encoder");
197 return false;
198 } else {
199 TRACE(4, "H264\tEncoder\tx264 encoder successfully opened");
200 }
201 #endif
202 return true;
203 }
204
Uninitialise()205 void X264EncoderContext::Uninitialise()
206 {
207 if (_codec != NULL)
208 {
209 X264_ENCODER_CLOSE(_codec);
210 TRACE(4, "H264\tEncoder\tClosed H.264 encoder, encoded " << _frameCounter << " Frames" );
211 _codec = NULL;
212 }
213 if (_txH264Frame) delete _txH264Frame;
214 }
215
SetMaxRTPFrameSize(unsigned size)216 void X264EncoderContext::SetMaxRTPFrameSize(unsigned size)
217 {
218 _txH264Frame->SetMaxPayloadSize(size);
219 }
220
SetMaxKeyFramePeriod(unsigned period)221 void X264EncoderContext::SetMaxKeyFramePeriod (unsigned period)
222 {
223 _IFrameInterval = _context.i_keyint_max = period;
224 _PFramesSinceLastIFrame = _IFrameInterval + 1; // force a keyframe on the first frame
225 TRACE(4, "H264\tEncoder\tx264 encoder key frame period set to " << period);
226 }
227
SetTargetBitrate(unsigned rate)228 void X264EncoderContext::SetTargetBitrate(unsigned rate)
229 {
230 _context.rc.i_bitrate = rate;
231 TRACE(4, "H264\tEncoder\tx264 encoder bitrate set to " << rate);
232 }
233
SetFrameWidth(unsigned width)234 void X264EncoderContext::SetFrameWidth(unsigned width)
235 {
236 _context.i_width = width;
237 TRACE(4, "H264\tEncoder\tx264 encoder width set to " << width);
238 }
239
SetFrameHeight(unsigned height)240 void X264EncoderContext::SetFrameHeight(unsigned height)
241 {
242 _context.i_height = height;
243 TRACE(4, "H264\tEncoder\tx264 encoder height set to " << height);
244 }
245
SetFrameRate(unsigned rate)246 void X264EncoderContext::SetFrameRate(unsigned rate)
247 {
248 _context.i_fps_num = rate;
249 _context.i_fps_den = 1;
250 TRACE(4, "H264\tEncoder\tx264 encoder frame rate set to " << (_context.i_fps_num/_context.i_fps_den));
251 }
252
SetTSTO(unsigned tsto)253 void X264EncoderContext::SetTSTO (unsigned tsto)
254 {
255 _context.rc.i_qp_min = H264_MIN_QUANT;
256 if (tsto > 0)
257 _context.rc.i_qp_max = (int)((51 - H264_MIN_QUANT) / 31 * tsto + H264_MIN_QUANT);
258 _context.rc.i_qp_step = 4;
259 TRACE(4, "H264\tEncoder\tx264 encoder QP range rate set to [" << _context.rc.i_qp_min << "-" << _context.rc.i_qp_max << "] with a step of " << _context.rc.i_qp_step);
260 }
261
SetProfileLevel(unsigned profileLevel)262 void X264EncoderContext::SetProfileLevel (unsigned profileLevel)
263 {
264 // unsigned profile = (profileLevel & 0xff0000) >> 16;
265 // bool constraint0 = (profileLevel & 0x008000) ? true : false;
266 // bool constraint1 = (profileLevel & 0x004000) ? true : false;
267 // bool constraint2 = (profileLevel & 0x002000) ? true : false;
268 // bool constraint3 = (profileLevel & 0x001000) ? true : false;
269 unsigned level = (profileLevel & 0x0000ff);
270
271 int i = 0;
272 while (h264_levels[i].level_idc) {
273 if (h264_levels[i].level_idc == level)
274 break;
275 i++;
276 }
277
278 if (!h264_levels[i].level_idc) {
279 TRACE(1, "H264\tCap\tIllegal Level negotiated");
280 return;
281 }
282
283 // We make use of the baseline profile, that means:
284 // no B-Frames (too much latency in interactive video)
285 // CBR (we want to get the max. quality making use of all the bitrate that is available)
286 // baseline profile begin
287 _context.b_cabac = 0; // Only >= MAIN LEVEL
288 _context.i_bframe = 0; // Only >= MAIN LEVEL
289
290 // Level:
291 _context.i_level_idc = level;
292
293 TRACE(4, "H264\tEncoder\tx264 encoder level set to " << _context.i_level_idc);
294 }
295
ApplyOptions()296 void X264EncoderContext::ApplyOptions()
297 {
298
299 #if X264_DELAYLOAD
300 return; // We apply options when we do our first encode
301 #else
302 if (_codec != NULL)
303 X264_ENCODER_CLOSE(_codec);
304
305 _codec = X264_ENCODER_OPEN(&_context);
306 if (_codec == NULL) {
307 TRACE(1, "H264\tEncoder\tCouldn't init x264 encoder");
308 }
309 TRACE(4, "H264\tEncoder\tx264 encoder successfully opened");
310 #endif
311
312 }
313
fastUpdateRequested(void)314 void X264EncoderContext::fastUpdateRequested(void)
315 {
316 _fastUpdateRequested = true;
317 }
318
SetMaxNALSize(unsigned size)319 void X264EncoderContext::SetMaxNALSize (unsigned size)
320 {
321 _txH264Frame->SetMaxPayloadSize(size);
322 _context.i_slice_max_size = size;
323 }
324
EncodeFrames(const unsigned char * src,unsigned & srcLen,unsigned char * dst,unsigned & dstLen,unsigned int & flags)325 int X264EncoderContext::EncodeFrames(const unsigned char * src, unsigned & srcLen, unsigned char * dst, unsigned & dstLen, unsigned int & flags)
326 {
327
328 // create RTP frame from source buffer
329 RTPFrame srcRTP(src, srcLen);
330
331 // create RTP frame from destination buffer
332 RTPFrame dstRTP(dst, dstLen);
333
334 dstLen = 0;
335
336 // from here, we are encoding a new frame
337 if (
338 #ifndef X264_DELAYLOAD
339 (!_codec) ||
340 #endif
341 (!_txH264Frame))
342 {
343 return 0;
344 }
345
346 // if there are RTP packets to return, return them
347 if (_txH264Frame->HasRTPFrames())
348 {
349 _txH264Frame->GetRTPFrame(dstRTP, flags);
350 dstLen = dstRTP.GetFrameLen();
351 return 1;
352 }
353
354 if (srcRTP.GetPayloadSize() < sizeof(frameHeader))
355 {
356 TRACE(1, "H264\tEncoder\tVideo grab too small, Close down video transmission thread");
357 return 0;
358 }
359
360 frameHeader * header = (frameHeader *)srcRTP.GetPayloadPtr();
361 if (header->x != 0 || header->y != 0)
362 {
363 TRACE(1, "H264\tEncoder\tVideo grab of partial frame unsupported, Close down video transmission thread");
364 return 0;
365 }
366
367 x264_nal_t* NALs;
368 int numberOfNALs = 0;
369
370 // do a validation of size
371 // if the incoming data has changed size, tell the encoder
372 if (!_codec || (unsigned)_context.i_width != header->width || (unsigned)_context.i_height != header->height)
373 {
374 if (_codec)
375 X264_ENCODER_CLOSE(_codec);
376 _context.i_width = header->width;
377 _context.i_height = header->height;
378 _codec = X264_ENCODER_OPEN(&_context);
379 if (_codec == NULL) {
380 TRACE(1, "H264\tEncoder\tCouldn't init x264 encoder");
381 return 0;
382 }
383 #if X264_DELAYLOAD
384 TRACE(4, "H264\tEncoder\tx264 encoder successfully opened");
385 #endif
386 }
387
388 bool wantIFrame = _fastUpdateRequested;
389 _fastUpdateRequested = false;
390
391 x264_picture_t dummyOutput;
392 #if X264_BUILD >= 98
393 // starting with build 98 applications who allocate a x264_picture_t themselves have to call x264_picture_init()
394 X264_PICTURE_INIT(&dummyOutput);
395 #endif
396
397 // Check whether to insert a keyframe
398 // (On the first frame and every_IFrameInterval)
399 _PFramesSinceLastIFrame++;
400 if (_PFramesSinceLastIFrame >= _IFrameInterval)
401 {
402 wantIFrame = true;
403 _PFramesSinceLastIFrame = 0;
404 }
405 // Prepare the frame to be encoded
406 _inputFrame.img.plane[0] = (uint8_t *)(((unsigned char *)header) + sizeof(frameHeader));
407 _inputFrame.img.i_stride[0] = header->width;
408 _inputFrame.img.plane[1] = (uint8_t *)((((unsigned char *)header) + sizeof(frameHeader))
409 + (int)(_inputFrame.img.i_stride[0]*header->height));
410 _inputFrame.img.i_stride[1] =
411 _inputFrame.img.i_stride[2] = (int) ( header->width / 2 );
412 _inputFrame.img.plane[2] = (uint8_t *)(_inputFrame.img.plane[1] + (int)(_inputFrame.img.i_stride[1] *header->height/2));
413 _inputFrame.i_type = (wantIFrame || (flags & forceIFrame)) ? X264_TYPE_IDR : X264_TYPE_AUTO;
414 _inputFrame.i_pts = _frameCounter; // x264 needs a time reference
415
416 #if X264_BUILD > 79
417 _inputFrame.param = NULL; // &_context;
418 #endif
419 //TRACE (1,"H264\tEncoder\t" << numberOfNALs);
420 while (numberOfNALs==0) { // workaround for first 2 packets being 0
421 if (X264_ENCODER_ENCODE(_codec, &NALs, &numberOfNALs, &_inputFrame, &dummyOutput) < 0) {
422 TRACE (1,"H264\tEncoder\tEncoding failed");
423 return 0;
424 }
425 }
426
427 _txH264Frame->BeginNewFrame();
428 #ifndef LICENCE_MPL
429 _txH264Frame->SetFromFrame(NALs, numberOfNALs);
430 #endif
431 _txH264Frame->SetTimestamp(srcRTP.GetTimestamp()); // BUG: not set in srcRTP
432 _frameCounter++;
433
434 if (_txH264Frame->HasRTPFrames())
435 {
436 _txH264Frame->GetRTPFrame(dstRTP, flags);
437 dstLen = dstRTP.GetFrameLen();
438 return 1;
439 }
440 return 1;
441 }
442