diff options
Diffstat (limited to 'toxav/video.c')
-rw-r--r-- | toxav/video.c | 292 |
1 files changed, 233 insertions, 59 deletions
diff --git a/toxav/video.c b/toxav/video.c index eee542a2..0014dbb6 100644 --- a/toxav/video.c +++ b/toxav/video.c | |||
@@ -33,8 +33,124 @@ | |||
33 | #include <assert.h> | 33 | #include <assert.h> |
34 | #include <stdlib.h> | 34 | #include <stdlib.h> |
35 | 35 | ||
36 | #define MAX_DECODE_TIME_US 0 /* Good quality encode. */ | 36 | /** |
37 | #define VIDEO_DECODE_BUFFER_SIZE 20 | 37 | * Soft deadline the decoder should attempt to meet, in "us" (microseconds). |
38 | * Set to zero for unlimited. | ||
39 | * | ||
40 | * By convention, the value 1 is used to mean "return as fast as possible." | ||
41 | */ | ||
42 | // TODO: don't hardcode this, let the application choose it | ||
43 | #define WANTED_MAX_DECODER_FPS 40 | ||
44 | |||
45 | /** | ||
46 | * VPX_DL_REALTIME (1) | ||
47 | * deadline parameter analogous to VPx REALTIME mode. | ||
48 | * | ||
49 | * VPX_DL_GOOD_QUALITY (1000000) | ||
50 | * deadline parameter analogous to VPx GOOD QUALITY mode. | ||
51 | * | ||
52 | * VPX_DL_BEST_QUALITY (0) | ||
53 | * deadline parameter analogous to VPx BEST QUALITY mode. | ||
54 | */ | ||
55 | #define MAX_DECODE_TIME_US (1000000 / WANTED_MAX_DECODER_FPS) // to allow x fps | ||
56 | |||
57 | /** | ||
58 | * Codec control function to set encoder internal speed settings. Changes in | ||
59 | * this value influences, among others, the encoder's selection of motion | ||
60 | * estimation methods. Values greater than 0 will increase encoder speed at the | ||
61 | * expense of quality. | ||
62 | * | ||
63 | * Note Valid range for VP8: -16..16 | ||
64 | */ | ||
65 | #define VP8E_SET_CPUUSED_VALUE 16 | ||
66 | |||
67 | /** | ||
68 | * Initialize encoder with this value. Target bandwidth to use for this stream, in kilobits per second. | ||
69 | */ | ||
70 | #define VIDEO_BITRATE_INITIAL_VALUE 5000 | ||
71 | #define VIDEO_DECODE_BUFFER_SIZE 5 // this buffer has normally max. 1 entry | ||
72 | |||
73 | #define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx()) | ||
74 | #define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) | ||
75 | |||
76 | #define VIDEO_CODEC_DECODER_MAX_WIDTH 800 // its a dummy value, because the struct needs a value there | ||
77 | #define VIDEO_CODEC_DECODER_MAX_HEIGHT 600 // its a dummy value, because the struct needs a value there | ||
78 | |||
79 | #define VPX_MAX_DIST_NORMAL 40 | ||
80 | #define VPX_MAX_DIST_START 40 | ||
81 | |||
82 | #define VPX_MAX_ENCODER_THREADS 4 | ||
83 | #define VPX_MAX_DECODER_THREADS 4 | ||
84 | #define VIDEO__VP8_DECODER_POST_PROCESSING_ENABLED 0 | ||
85 | |||
86 | void vc_init_encoder_cfg(Logger *log, vpx_codec_enc_cfg_t *cfg, int16_t kf_max_dist) | ||
87 | { | ||
88 | vpx_codec_err_t rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, cfg, 0); | ||
89 | |||
90 | if (rc != VPX_CODEC_OK) { | ||
91 | LOGGER_ERROR(log, "vc_init_encoder_cfg:Failed to get config: %s", vpx_codec_err_to_string(rc)); | ||
92 | } | ||
93 | |||
94 | /* Target bandwidth to use for this stream, in kilobits per second */ | ||
95 | cfg->rc_target_bitrate = VIDEO_BITRATE_INITIAL_VALUE; | ||
96 | cfg->g_w = VIDEO_CODEC_DECODER_MAX_WIDTH; | ||
97 | cfg->g_h = VIDEO_CODEC_DECODER_MAX_HEIGHT; | ||
98 | cfg->g_pass = VPX_RC_ONE_PASS; | ||
99 | cfg->g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS; | ||
100 | cfg->g_lag_in_frames = 0; | ||
101 | |||
102 | /* Allow lagged encoding | ||
103 | * | ||
104 | * If set, this value allows the encoder to consume a number of input | ||
105 | * frames before producing output frames. This allows the encoder to | ||
106 | * base decisions for the current frame on future frames. This does | ||
107 | * increase the latency of the encoding pipeline, so it is not appropriate | ||
108 | * in all situations (ex: realtime encoding). | ||
109 | * | ||
110 | * Note that this is a maximum value -- the encoder may produce frames | ||
111 | * sooner than the given limit. Set this value to 0 to disable this | ||
112 | * feature. | ||
113 | */ | ||
114 | cfg->kf_min_dist = 0; | ||
115 | cfg->kf_mode = VPX_KF_AUTO; // Encoder determines optimal placement automatically | ||
116 | cfg->rc_end_usage = VPX_VBR; // what quality mode? | ||
117 | |||
118 | /* | ||
119 | * VPX_VBR Variable Bit Rate (VBR) mode | ||
120 | * VPX_CBR Constant Bit Rate (CBR) mode | ||
121 | * VPX_CQ Constrained Quality (CQ) mode -> give codec a hint that we may be on low bandwidth connection | ||
122 | * VPX_Q Constant Quality (Q) mode | ||
123 | */ | ||
124 | if (kf_max_dist > 1) { | ||
125 | cfg->kf_max_dist = kf_max_dist; // a full frame every x frames minimum (can be more often, codec decides automatically) | ||
126 | LOGGER_DEBUG(log, "kf_max_dist=%d (1)", cfg->kf_max_dist); | ||
127 | } else { | ||
128 | cfg->kf_max_dist = VPX_MAX_DIST_START; | ||
129 | LOGGER_DEBUG(log, "kf_max_dist=%d (2)", cfg->kf_max_dist); | ||
130 | } | ||
131 | |||
132 | cfg->g_threads = VPX_MAX_ENCODER_THREADS; // Maximum number of threads to use | ||
133 | /* TODO: set these to something reasonable */ | ||
134 | // cfg->g_timebase.num = 1; | ||
135 | // cfg->g_timebase.den = 60; // 60 fps | ||
136 | cfg->rc_resize_allowed = 1; // allow encoder to resize to smaller resolution | ||
137 | cfg->rc_resize_up_thresh = 40; | ||
138 | cfg->rc_resize_down_thresh = 5; | ||
139 | |||
140 | /* TODO: make quality setting an API call, but start with normal quality */ | ||
141 | #if 0 | ||
142 | /* Highest-resolution encoder settings */ | ||
143 | cfg->rc_dropframe_thresh = 0; | ||
144 | cfg->rc_resize_allowed = 0; | ||
145 | cfg->rc_min_quantizer = 2; | ||
146 | cfg->rc_max_quantizer = 56; | ||
147 | cfg->rc_undershoot_pct = 100; | ||
148 | cfg->rc_overshoot_pct = 15; | ||
149 | cfg->rc_buf_initial_sz = 500; | ||
150 | cfg->rc_buf_optimal_sz = 600; | ||
151 | cfg->rc_buf_sz = 1000; | ||
152 | #endif | ||
153 | } | ||
38 | 154 | ||
39 | VCSession *vc_new(Logger *log, ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data) | 155 | VCSession *vc_new(Logger *log, ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data) |
40 | { | 156 | { |
@@ -52,49 +168,72 @@ VCSession *vc_new(Logger *log, ToxAV *av, uint32_t friend_number, toxav_video_re | |||
52 | return nullptr; | 168 | return nullptr; |
53 | } | 169 | } |
54 | 170 | ||
171 | int cpu_used_value = VP8E_SET_CPUUSED_VALUE; | ||
172 | |||
55 | if (!(vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE))) { | 173 | if (!(vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE))) { |
56 | goto BASE_CLEANUP; | 174 | goto BASE_CLEANUP; |
57 | } | 175 | } |
58 | 176 | ||
59 | rc = vpx_codec_dec_init(vc->decoder, VIDEO_CODEC_DECODER_INTERFACE, nullptr, 0); | 177 | /* |
178 | * VPX_CODEC_USE_FRAME_THREADING | ||
179 | * Enable frame-based multi-threading | ||
180 | * | ||
181 | * VPX_CODEC_USE_ERROR_CONCEALMENT | ||
182 | * Conceal errors in decoded frames | ||
183 | */ | ||
184 | vpx_codec_dec_cfg_t dec_cfg; | ||
185 | dec_cfg.threads = VPX_MAX_DECODER_THREADS; // Maximum number of threads to use | ||
186 | dec_cfg.w = VIDEO_CODEC_DECODER_MAX_WIDTH; | ||
187 | dec_cfg.h = VIDEO_CODEC_DECODER_MAX_HEIGHT; | ||
188 | |||
189 | LOGGER_DEBUG(log, "Using VP8 codec for decoder (0)"); | ||
190 | rc = vpx_codec_dec_init(vc->decoder, VIDEO_CODEC_DECODER_INTERFACE, &dec_cfg, | ||
191 | VPX_CODEC_USE_FRAME_THREADING | VPX_CODEC_USE_POSTPROC); | ||
192 | |||
193 | if (rc == VPX_CODEC_INCAPABLE) { | ||
194 | LOGGER_WARNING(log, "Postproc not supported by this decoder (0)"); | ||
195 | rc = vpx_codec_dec_init(vc->decoder, VIDEO_CODEC_DECODER_INTERFACE, &dec_cfg, VPX_CODEC_USE_FRAME_THREADING); | ||
196 | } | ||
60 | 197 | ||
61 | if (rc != VPX_CODEC_OK) { | 198 | if (rc != VPX_CODEC_OK) { |
62 | LOGGER_ERROR(log, "Init video_decoder failed: %s", vpx_codec_err_to_string(rc)); | 199 | LOGGER_ERROR(log, "Init video_decoder failed: %s", vpx_codec_err_to_string(rc)); |
63 | goto BASE_CLEANUP; | 200 | goto BASE_CLEANUP; |
64 | } | 201 | } |
65 | 202 | ||
66 | /* Set encoder to some initial values | 203 | if (VIDEO__VP8_DECODER_POST_PROCESSING_ENABLED == 1) { |
67 | */ | 204 | vp8_postproc_cfg_t pp = {VP8_DEBLOCK, 1, 0}; |
68 | vpx_codec_enc_cfg_t cfg; | 205 | vpx_codec_err_t cc_res = vpx_codec_control(vc->decoder, VP8_SET_POSTPROC, &pp); |
69 | rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | ||
70 | 206 | ||
71 | if (rc != VPX_CODEC_OK) { | 207 | if (cc_res != VPX_CODEC_OK) { |
72 | LOGGER_ERROR(log, "Failed to get config: %s", vpx_codec_err_to_string(rc)); | 208 | LOGGER_WARNING(log, "Failed to turn on postproc"); |
73 | goto BASE_CLEANUP_1; | 209 | } else { |
210 | LOGGER_DEBUG(log, "turn on postproc: OK"); | ||
211 | } | ||
212 | } else { | ||
213 | vp8_postproc_cfg_t pp = {0, 0, 0}; | ||
214 | vpx_codec_err_t cc_res = vpx_codec_control(vc->decoder, VP8_SET_POSTPROC, &pp); | ||
215 | |||
216 | if (cc_res != VPX_CODEC_OK) { | ||
217 | LOGGER_WARNING(log, "Failed to turn OFF postproc"); | ||
218 | } else { | ||
219 | LOGGER_DEBUG(log, "Disable postproc: OK"); | ||
220 | } | ||
74 | } | 221 | } |
75 | 222 | ||
76 | cfg.rc_target_bitrate = 500000; | 223 | /* Set encoder to some initial values |
77 | cfg.g_w = 800; | 224 | */ |
78 | cfg.g_h = 600; | 225 | vpx_codec_enc_cfg_t cfg; |
79 | cfg.g_pass = VPX_RC_ONE_PASS; | 226 | vc_init_encoder_cfg(log, &cfg, 1); |
80 | /* TODO(mannol): If we set error resilience the app will crash due to bug in vp8. | ||
81 | Perhaps vp9 has solved it?*/ | ||
82 | #if 0 | ||
83 | cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS; | ||
84 | #endif | ||
85 | cfg.g_lag_in_frames = 0; | ||
86 | cfg.kf_min_dist = 0; | ||
87 | cfg.kf_max_dist = 48; | ||
88 | cfg.kf_mode = VPX_KF_AUTO; | ||
89 | 227 | ||
90 | rc = vpx_codec_enc_init(vc->encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | 228 | LOGGER_DEBUG(log, "Using VP8 codec for encoder (0.1)"); |
229 | rc = vpx_codec_enc_init(vc->encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, VPX_CODEC_USE_FRAME_THREADING); | ||
91 | 230 | ||
92 | if (rc != VPX_CODEC_OK) { | 231 | if (rc != VPX_CODEC_OK) { |
93 | LOGGER_ERROR(log, "Failed to initialize encoder: %s", vpx_codec_err_to_string(rc)); | 232 | LOGGER_ERROR(log, "Failed to initialize encoder: %s", vpx_codec_err_to_string(rc)); |
94 | goto BASE_CLEANUP_1; | 233 | goto BASE_CLEANUP_1; |
95 | } | 234 | } |
96 | 235 | ||
97 | rc = vpx_codec_control(vc->encoder, VP8E_SET_CPUUSED, 8); | 236 | rc = vpx_codec_control(vc->encoder, VP8E_SET_CPUUSED, cpu_used_value); |
98 | 237 | ||
99 | if (rc != VPX_CODEC_OK) { | 238 | if (rc != VPX_CODEC_OK) { |
100 | LOGGER_ERROR(log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | 239 | LOGGER_ERROR(log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); |
@@ -102,6 +241,20 @@ VCSession *vc_new(Logger *log, ToxAV *av, uint32_t friend_number, toxav_video_re | |||
102 | goto BASE_CLEANUP_1; | 241 | goto BASE_CLEANUP_1; |
103 | } | 242 | } |
104 | 243 | ||
244 | /* | ||
245 | VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY, unsigned int) | ||
246 | control function to set noise sensitivity | ||
247 | 0: off, 1: OnYOnly, 2: OnYUV, 3: OnYUVAggressive, 4: Adaptive | ||
248 | */ | ||
249 | /* | ||
250 | rc = vpx_codec_control(vc->encoder, VP8E_SET_NOISE_SENSITIVITY, 2); | ||
251 | |||
252 | if (rc != VPX_CODEC_OK) { | ||
253 | LOGGER_ERROR(log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | ||
254 | vpx_codec_destroy(vc->encoder); | ||
255 | goto BASE_CLEANUP_1; | ||
256 | } | ||
257 | */ | ||
105 | vc->linfts = current_time_monotonic(); | 258 | vc->linfts = current_time_monotonic(); |
106 | vc->lcfd = 60; | 259 | vc->lcfd = 60; |
107 | vc->vcb.first = cb; | 260 | vc->vcb.first = cb; |
@@ -109,9 +262,7 @@ VCSession *vc_new(Logger *log, ToxAV *av, uint32_t friend_number, toxav_video_re | |||
109 | vc->friend_number = friend_number; | 262 | vc->friend_number = friend_number; |
110 | vc->av = av; | 263 | vc->av = av; |
111 | vc->log = log; | 264 | vc->log = log; |
112 | |||
113 | return vc; | 265 | return vc; |
114 | |||
115 | BASE_CLEANUP_1: | 266 | BASE_CLEANUP_1: |
116 | vpx_codec_destroy(vc->decoder); | 267 | vpx_codec_destroy(vc->decoder); |
117 | BASE_CLEANUP: | 268 | BASE_CLEANUP: |
@@ -120,6 +271,7 @@ BASE_CLEANUP: | |||
120 | free(vc); | 271 | free(vc); |
121 | return nullptr; | 272 | return nullptr; |
122 | } | 273 | } |
274 | |||
123 | void vc_kill(VCSession *vc) | 275 | void vc_kill(VCSession *vc) |
124 | { | 276 | { |
125 | if (!vc) { | 277 | if (!vc) { |
@@ -128,7 +280,6 @@ void vc_kill(VCSession *vc) | |||
128 | 280 | ||
129 | vpx_codec_destroy(vc->encoder); | 281 | vpx_codec_destroy(vc->encoder); |
130 | vpx_codec_destroy(vc->decoder); | 282 | vpx_codec_destroy(vc->decoder); |
131 | |||
132 | void *p; | 283 | void *p; |
133 | 284 | ||
134 | while (rb_read((RingBuffer *)vc->vbuf_raw, &p)) { | 285 | while (rb_read((RingBuffer *)vc->vbuf_raw, &p)) { |
@@ -136,12 +287,11 @@ void vc_kill(VCSession *vc) | |||
136 | } | 287 | } |
137 | 288 | ||
138 | rb_kill((RingBuffer *)vc->vbuf_raw); | 289 | rb_kill((RingBuffer *)vc->vbuf_raw); |
139 | |||
140 | pthread_mutex_destroy(vc->queue_mutex); | 290 | pthread_mutex_destroy(vc->queue_mutex); |
141 | |||
142 | LOGGER_DEBUG(vc->log, "Terminated video handler: %p", vc); | 291 | LOGGER_DEBUG(vc->log, "Terminated video handler: %p", vc); |
143 | free(vc); | 292 | free(vc); |
144 | } | 293 | } |
294 | |||
145 | void vc_iterate(VCSession *vc) | 295 | void vc_iterate(VCSession *vc) |
146 | { | 296 | { |
147 | if (!vc) { | 297 | if (!vc) { |
@@ -154,45 +304,63 @@ void vc_iterate(VCSession *vc) | |||
154 | 304 | ||
155 | pthread_mutex_lock(vc->queue_mutex); | 305 | pthread_mutex_lock(vc->queue_mutex); |
156 | 306 | ||
307 | uint32_t full_data_len; | ||
308 | |||
157 | if (rb_read((RingBuffer *)vc->vbuf_raw, (void **)&p)) { | 309 | if (rb_read((RingBuffer *)vc->vbuf_raw, (void **)&p)) { |
158 | pthread_mutex_unlock(vc->queue_mutex); | 310 | pthread_mutex_unlock(vc->queue_mutex); |
311 | const struct RTPHeader *const header = &p->header; | ||
312 | |||
313 | if (header->flags & RTP_LARGE_FRAME) { | ||
314 | full_data_len = header->data_length_full; | ||
315 | LOGGER_DEBUG(vc->log, "vc_iterate:001:full_data_len=%d", (int)full_data_len); | ||
316 | } else { | ||
317 | full_data_len = p->len; | ||
318 | LOGGER_DEBUG(vc->log, "vc_iterate:002"); | ||
319 | } | ||
159 | 320 | ||
160 | rc = vpx_codec_decode(vc->decoder, p->data, p->len, nullptr, MAX_DECODE_TIME_US); | 321 | LOGGER_DEBUG(vc->log, "vc_iterate: rb_read p->len=%d p->header.xe=%d", (int)full_data_len, p->header.xe); |
322 | LOGGER_DEBUG(vc->log, "vc_iterate: rb_read rb size=%d", (int)rb_size((RingBuffer *)vc->vbuf_raw)); | ||
323 | rc = vpx_codec_decode(vc->decoder, p->data, full_data_len, nullptr, MAX_DECODE_TIME_US); | ||
161 | free(p); | 324 | free(p); |
162 | 325 | ||
163 | if (rc != VPX_CODEC_OK) { | 326 | if (rc != VPX_CODEC_OK) { |
164 | LOGGER_ERROR(vc->log, "Error decoding video: %s", vpx_codec_err_to_string(rc)); | 327 | LOGGER_ERROR(vc->log, "Error decoding video: %d %s", (int)rc, vpx_codec_err_to_string(rc)); |
165 | } else { | 328 | } else { |
329 | /* Play decoded images */ | ||
166 | vpx_codec_iter_t iter = nullptr; | 330 | vpx_codec_iter_t iter = nullptr; |
167 | vpx_image_t *dest = vpx_codec_get_frame(vc->decoder, &iter); | 331 | vpx_image_t *dest = nullptr; |
168 | 332 | ||
169 | /* Play decoded images */ | 333 | while ((dest = vpx_codec_get_frame(vc->decoder, &iter)) != nullptr) { |
170 | for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) { | ||
171 | if (vc->vcb.first) { | 334 | if (vc->vcb.first) { |
172 | vc->vcb.first(vc->av, vc->friend_number, dest->d_w, dest->d_h, | 335 | vc->vcb.first(vc->av, vc->friend_number, dest->d_w, dest->d_h, |
173 | (const uint8_t *)dest->planes[0], (const uint8_t *)dest->planes[1], (const uint8_t *)dest->planes[2], | 336 | (const uint8_t *)dest->planes[0], (const uint8_t *)dest->planes[1], (const uint8_t *)dest->planes[2], |
174 | dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second); | 337 | dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second); |
175 | } | 338 | } |
176 | 339 | ||
177 | vpx_img_free(dest); | 340 | vpx_img_free(dest); // is this needed? none of the VPx examples show that |
178 | } | 341 | } |
179 | } | 342 | } |
180 | 343 | ||
181 | return; | 344 | return; |
345 | } else { | ||
346 | LOGGER_TRACE(vc->log, "no Video frame data available"); | ||
182 | } | 347 | } |
183 | 348 | ||
184 | pthread_mutex_unlock(vc->queue_mutex); | 349 | pthread_mutex_unlock(vc->queue_mutex); |
185 | } | 350 | } |
351 | |||
186 | int vc_queue_message(void *vcp, struct RTPMessage *msg) | 352 | int vc_queue_message(void *vcp, struct RTPMessage *msg) |
187 | { | 353 | { |
188 | /* This function does the reconstruction of video packets. | 354 | /* This function is called with complete messages |
189 | * See more info about video splitting in docs | 355 | * they have already been assembled. |
356 | * this function gets called from handle_rtp_packet() and handle_rtp_packet_v3() | ||
190 | */ | 357 | */ |
191 | if (!vcp || !msg) { | 358 | if (!vcp || !msg) { |
192 | return -1; | 359 | return -1; |
193 | } | 360 | } |
194 | 361 | ||
195 | VCSession *vc = (VCSession *)vcp; | 362 | VCSession *vc = (VCSession *)vcp; |
363 | const struct RTPHeader *const header = &msg->header; | ||
196 | 364 | ||
197 | if (msg->header.pt == (rtp_TypeVideo + 2) % 128) { | 365 | if (msg->header.pt == (rtp_TypeVideo + 2) % 128) { |
198 | LOGGER_WARNING(vc->log, "Got dummy!"); | 366 | LOGGER_WARNING(vc->log, "Got dummy!"); |
@@ -201,41 +369,45 @@ int vc_queue_message(void *vcp, struct RTPMessage *msg) | |||
201 | } | 369 | } |
202 | 370 | ||
203 | if (msg->header.pt != rtp_TypeVideo % 128) { | 371 | if (msg->header.pt != rtp_TypeVideo % 128) { |
204 | LOGGER_WARNING(vc->log, "Invalid payload type!"); | 372 | LOGGER_WARNING(vc->log, "Invalid payload type! pt=%d", (int)msg->header.pt); |
205 | free(msg); | 373 | free(msg); |
206 | return -1; | 374 | return -1; |
207 | } | 375 | } |
208 | 376 | ||
209 | pthread_mutex_lock(vc->queue_mutex); | 377 | pthread_mutex_lock(vc->queue_mutex); |
210 | free(rb_write((RingBuffer *)vc->vbuf_raw, msg)); | 378 | |
211 | { | 379 | if ((header->flags & RTP_LARGE_FRAME) && header->pt == rtp_TypeVideo % 128) { |
212 | /* Calculate time took for peer to send us this frame */ | 380 | LOGGER_DEBUG(vc->log, "rb_write msg->len=%d b0=%d b1=%d", (int)msg->len, (int)msg->data[0], (int)msg->data[1]); |
213 | uint32_t t_lcfd = current_time_monotonic() - vc->linfts; | ||
214 | vc->lcfd = t_lcfd > 100 ? vc->lcfd : t_lcfd; | ||
215 | vc->linfts = current_time_monotonic(); | ||
216 | } | 381 | } |
217 | pthread_mutex_unlock(vc->queue_mutex); | ||
218 | 382 | ||
383 | free(rb_write((RingBuffer *)vc->vbuf_raw, msg)); | ||
384 | |||
385 | /* Calculate time it took for peer to send us this frame */ | ||
386 | uint32_t t_lcfd = current_time_monotonic() - vc->linfts; | ||
387 | vc->lcfd = t_lcfd > 100 ? vc->lcfd : t_lcfd; | ||
388 | vc->linfts = current_time_monotonic(); | ||
389 | pthread_mutex_unlock(vc->queue_mutex); | ||
219 | return 0; | 390 | return 0; |
220 | } | 391 | } |
221 | int vc_reconfigure_encoder(VCSession *vc, uint32_t bit_rate, uint16_t width, uint16_t height) | 392 | |
393 | int vc_reconfigure_encoder(VCSession *vc, uint32_t bit_rate, uint16_t width, uint16_t height, int16_t kf_max_dist) | ||
222 | { | 394 | { |
223 | if (!vc) { | 395 | if (!vc) { |
224 | return -1; | 396 | return -1; |
225 | } | 397 | } |
226 | 398 | ||
227 | vpx_codec_enc_cfg_t cfg = *vc->encoder->config.enc; | 399 | vpx_codec_enc_cfg_t cfg2 = *vc->encoder->config.enc; |
228 | vpx_codec_err_t rc; | 400 | vpx_codec_err_t rc; |
229 | 401 | ||
230 | if (cfg.rc_target_bitrate == bit_rate && cfg.g_w == width && cfg.g_h == height) { | 402 | if (cfg2.rc_target_bitrate == bit_rate && cfg2.g_w == width && cfg2.g_h == height && kf_max_dist == -1) { |
231 | return 0; /* Nothing changed */ | 403 | return 0; /* Nothing changed */ |
232 | } | 404 | } |
233 | 405 | ||
234 | if (cfg.g_w == width && cfg.g_h == height) { | 406 | if (cfg2.g_w == width && cfg2.g_h == height && kf_max_dist == -1) { |
235 | /* Only bit rate changed */ | 407 | /* Only bit rate changed */ |
236 | cfg.rc_target_bitrate = bit_rate; | 408 | LOGGER_INFO(vc->log, "bitrate change from: %u to: %u", (uint32_t)cfg2.rc_target_bitrate, (uint32_t)bit_rate); |
237 | 409 | cfg2.rc_target_bitrate = bit_rate; | |
238 | rc = vpx_codec_enc_config_set(vc->encoder, &cfg); | 410 | rc = vpx_codec_enc_config_set(vc->encoder, &cfg2); |
239 | 411 | ||
240 | if (rc != VPX_CODEC_OK) { | 412 | if (rc != VPX_CODEC_OK) { |
241 | LOGGER_ERROR(vc->log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | 413 | LOGGER_ERROR(vc->log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); |
@@ -245,23 +417,25 @@ int vc_reconfigure_encoder(VCSession *vc, uint32_t bit_rate, uint16_t width, uin | |||
245 | /* Resolution is changed, must reinitialize encoder since libvpx v1.4 doesn't support | 417 | /* Resolution is changed, must reinitialize encoder since libvpx v1.4 doesn't support |
246 | * reconfiguring encoder to use resolutions greater than initially set. | 418 | * reconfiguring encoder to use resolutions greater than initially set. |
247 | */ | 419 | */ |
248 | |||
249 | LOGGER_DEBUG(vc->log, "Have to reinitialize vpx encoder on session %p", vc); | 420 | LOGGER_DEBUG(vc->log, "Have to reinitialize vpx encoder on session %p", vc); |
250 | 421 | vpx_codec_ctx_t new_c; | |
422 | vpx_codec_enc_cfg_t cfg; | ||
423 | vc_init_encoder_cfg(vc->log, &cfg, kf_max_dist); | ||
251 | cfg.rc_target_bitrate = bit_rate; | 424 | cfg.rc_target_bitrate = bit_rate; |
252 | cfg.g_w = width; | 425 | cfg.g_w = width; |
253 | cfg.g_h = height; | 426 | cfg.g_h = height; |
254 | 427 | ||
255 | vpx_codec_ctx_t new_c; | 428 | LOGGER_DEBUG(vc->log, "Using VP8 codec for encoder"); |
256 | 429 | rc = vpx_codec_enc_init(&new_c, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, VPX_CODEC_USE_FRAME_THREADING); | |
257 | rc = vpx_codec_enc_init(&new_c, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | ||
258 | 430 | ||
259 | if (rc != VPX_CODEC_OK) { | 431 | if (rc != VPX_CODEC_OK) { |
260 | LOGGER_ERROR(vc->log, "Failed to initialize encoder: %s", vpx_codec_err_to_string(rc)); | 432 | LOGGER_ERROR(vc->log, "Failed to initialize encoder: %s", vpx_codec_err_to_string(rc)); |
261 | return -1; | 433 | return -1; |
262 | } | 434 | } |
263 | 435 | ||
264 | rc = vpx_codec_control(&new_c, VP8E_SET_CPUUSED, 8); | 436 | int cpu_used_value = VP8E_SET_CPUUSED_VALUE; |
437 | |||
438 | rc = vpx_codec_control(&new_c, VP8E_SET_CPUUSED, cpu_used_value); | ||
265 | 439 | ||
266 | if (rc != VPX_CODEC_OK) { | 440 | if (rc != VPX_CODEC_OK) { |
267 | LOGGER_ERROR(vc->log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | 441 | LOGGER_ERROR(vc->log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); |