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