OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 23 matching lines...) Expand all Loading... |
34 _receiver(_timing, | 34 _receiver(_timing, |
35 clock_, | 35 clock_, |
36 event_factory, | 36 event_factory, |
37 nack_sender, | 37 nack_sender, |
38 keyframe_request_sender), | 38 keyframe_request_sender), |
39 _decodedFrameCallback(_timing, clock_), | 39 _decodedFrameCallback(_timing, clock_), |
40 _frameTypeCallback(nullptr), | 40 _frameTypeCallback(nullptr), |
41 _receiveStatsCallback(nullptr), | 41 _receiveStatsCallback(nullptr), |
42 _decoderTimingCallback(nullptr), | 42 _decoderTimingCallback(nullptr), |
43 _packetRequestCallback(nullptr), | 43 _packetRequestCallback(nullptr), |
44 _decoder(nullptr), | |
45 _frameFromFile(), | 44 _frameFromFile(), |
46 _scheduleKeyRequest(false), | 45 _scheduleKeyRequest(false), |
47 drop_frames_until_keyframe_(false), | 46 drop_frames_until_keyframe_(false), |
48 max_nack_list_size_(0), | 47 max_nack_list_size_(0), |
49 _codecDataBase(nullptr), | 48 _codecDataBase(nullptr), |
50 pre_decode_image_callback_(pre_decode_image_callback), | 49 pre_decode_image_callback_(pre_decode_image_callback), |
51 _receiveStatsTimer(1000, clock_), | 50 _receiveStatsTimer(1000, clock_), |
52 _retransmissionTimer(10, clock_), | 51 _retransmissionTimer(10, clock_), |
53 _keyRequestTimer(500, clock_) {} | 52 _keyRequestTimer(500, clock_) {} |
54 | 53 |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 _receiver.SetDecodeErrorMode(kWithErrors); | 160 _receiver.SetDecodeErrorMode(kWithErrors); |
162 break; | 161 break; |
163 } | 162 } |
164 return VCM_OK; | 163 return VCM_OK; |
165 } | 164 } |
166 | 165 |
167 // Register a receive callback. Will be called whenever there is a new frame | 166 // Register a receive callback. Will be called whenever there is a new frame |
168 // ready for rendering. | 167 // ready for rendering. |
169 int32_t VideoReceiver::RegisterReceiveCallback( | 168 int32_t VideoReceiver::RegisterReceiveCallback( |
170 VCMReceiveCallback* receiveCallback) { | 169 VCMReceiveCallback* receiveCallback) { |
| 170 RTC_DCHECK(construction_thread_.CalledOnValidThread()); |
| 171 // TODO(tommi): Callback may be null, but only after the decoder thread has |
| 172 // been stopped. Use the signal we now get that tells us when the decoder |
| 173 // thread isn't running, to DCHECK that the method is never called while it |
| 174 // is. Once we're confident, we can remove the lock. |
171 rtc::CritScope cs(&receive_crit_); | 175 rtc::CritScope cs(&receive_crit_); |
172 _decodedFrameCallback.SetUserReceiveCallback(receiveCallback); | 176 _decodedFrameCallback.SetUserReceiveCallback(receiveCallback); |
173 return VCM_OK; | 177 return VCM_OK; |
174 } | 178 } |
175 | 179 |
176 int32_t VideoReceiver::RegisterReceiveStatisticsCallback( | 180 int32_t VideoReceiver::RegisterReceiveStatisticsCallback( |
177 VCMReceiveStatisticsCallback* receiveStats) { | 181 VCMReceiveStatisticsCallback* receiveStats) { |
| 182 RTC_DCHECK(construction_thread_.CalledOnValidThread()); |
178 rtc::CritScope cs(&process_crit_); | 183 rtc::CritScope cs(&process_crit_); |
179 _receiver.RegisterStatsCallback(receiveStats); | 184 _receiver.RegisterStatsCallback(receiveStats); |
180 _receiveStatsCallback = receiveStats; | 185 _receiveStatsCallback = receiveStats; |
181 return VCM_OK; | 186 return VCM_OK; |
182 } | 187 } |
183 | 188 |
184 int32_t VideoReceiver::RegisterDecoderTimingCallback( | 189 int32_t VideoReceiver::RegisterDecoderTimingCallback( |
185 VCMDecoderTimingCallback* decoderTiming) { | 190 VCMDecoderTimingCallback* decoderTiming) { |
| 191 RTC_DCHECK(construction_thread_.CalledOnValidThread()); |
186 rtc::CritScope cs(&process_crit_); | 192 rtc::CritScope cs(&process_crit_); |
187 _decoderTimingCallback = decoderTiming; | 193 _decoderTimingCallback = decoderTiming; |
188 return VCM_OK; | 194 return VCM_OK; |
189 } | 195 } |
190 | 196 |
191 // Register an externally defined decoder object. | 197 // Register an externally defined decoder object. |
192 void VideoReceiver::RegisterExternalDecoder(VideoDecoder* externalDecoder, | 198 void VideoReceiver::RegisterExternalDecoder(VideoDecoder* externalDecoder, |
193 uint8_t payloadType) { | 199 uint8_t payloadType) { |
| 200 RTC_DCHECK(construction_thread_.CalledOnValidThread()); |
| 201 // TODO(tommi): This method must be called when the decoder thread is not |
| 202 // running. Do we need a lock in that case? |
194 rtc::CritScope cs(&receive_crit_); | 203 rtc::CritScope cs(&receive_crit_); |
195 if (externalDecoder == nullptr) { | 204 if (externalDecoder == nullptr) { |
196 // Make sure the VCM updates the decoder next time it decodes. | |
197 _decoder = nullptr; | |
198 RTC_CHECK(_codecDataBase.DeregisterExternalDecoder(payloadType)); | 205 RTC_CHECK(_codecDataBase.DeregisterExternalDecoder(payloadType)); |
199 return; | 206 return; |
200 } | 207 } |
201 _codecDataBase.RegisterExternalDecoder(externalDecoder, payloadType); | 208 _codecDataBase.RegisterExternalDecoder(externalDecoder, payloadType); |
202 } | 209 } |
203 | 210 |
204 // Register a frame type request callback. | 211 // Register a frame type request callback. |
205 int32_t VideoReceiver::RegisterFrameTypeCallback( | 212 int32_t VideoReceiver::RegisterFrameTypeCallback( |
206 VCMFrameTypeCallback* frameTypeCallback) { | 213 VCMFrameTypeCallback* frameTypeCallback) { |
207 rtc::CritScope cs(&process_crit_); | 214 rtc::CritScope cs(&process_crit_); |
208 _frameTypeCallback = frameTypeCallback; | 215 _frameTypeCallback = frameTypeCallback; |
209 return VCM_OK; | 216 return VCM_OK; |
210 } | 217 } |
211 | 218 |
212 int32_t VideoReceiver::RegisterPacketRequestCallback( | 219 int32_t VideoReceiver::RegisterPacketRequestCallback( |
213 VCMPacketRequestCallback* callback) { | 220 VCMPacketRequestCallback* callback) { |
214 rtc::CritScope cs(&process_crit_); | 221 rtc::CritScope cs(&process_crit_); |
215 _packetRequestCallback = callback; | 222 _packetRequestCallback = callback; |
216 return VCM_OK; | 223 return VCM_OK; |
217 } | 224 } |
218 | 225 |
219 void VideoReceiver::TriggerDecoderShutdown() { | 226 void VideoReceiver::TriggerDecoderShutdown() { |
| 227 RTC_DCHECK(construction_thread_.CalledOnValidThread()); |
220 _receiver.TriggerDecoderShutdown(); | 228 _receiver.TriggerDecoderShutdown(); |
221 } | 229 } |
222 | 230 |
223 // Decode next frame, blocking. | 231 // Decode next frame, blocking. |
224 // Should be called as often as possible to get the most out of the decoder. | 232 // Should be called as often as possible to get the most out of the decoder. |
225 int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) { | 233 int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) { |
226 bool prefer_late_decoding = false; | 234 bool prefer_late_decoding = false; |
227 { | 235 { |
| 236 // TODO(tommi): Chances are that this lock isn't required. |
228 rtc::CritScope cs(&receive_crit_); | 237 rtc::CritScope cs(&receive_crit_); |
229 prefer_late_decoding = _codecDataBase.PrefersLateDecoding(); | 238 prefer_late_decoding = _codecDataBase.PrefersLateDecoding(); |
230 } | 239 } |
231 | 240 |
232 VCMEncodedFrame* frame = | 241 VCMEncodedFrame* frame = |
233 _receiver.FrameForDecoding(maxWaitTimeMs, prefer_late_decoding); | 242 _receiver.FrameForDecoding(maxWaitTimeMs, prefer_late_decoding); |
234 | 243 |
235 if (!frame) | 244 if (!frame) |
236 return VCM_FRAME_NOT_READY; | 245 return VCM_FRAME_NOT_READY; |
237 | 246 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 int qp = -1; | 294 int qp = -1; |
286 if (qp_parser_.GetQp(*frame, &qp)) { | 295 if (qp_parser_.GetQp(*frame, &qp)) { |
287 encoded_image.qp_ = qp; | 296 encoded_image.qp_ = qp; |
288 } | 297 } |
289 pre_decode_image_callback_->OnEncodedImage(encoded_image, | 298 pre_decode_image_callback_->OnEncodedImage(encoded_image, |
290 frame->CodecSpecific(), nullptr); | 299 frame->CodecSpecific(), nullptr); |
291 } | 300 } |
292 return Decode(*frame); | 301 return Decode(*frame); |
293 } | 302 } |
294 | 303 |
| 304 void VideoReceiver::DecodingStopped() { |
| 305 // No further calls to Decode() will be made after this point. |
| 306 // TODO(tommi): Make use of this to clarify and check threading model. |
| 307 } |
| 308 |
295 int32_t VideoReceiver::RequestSliceLossIndication( | 309 int32_t VideoReceiver::RequestSliceLossIndication( |
296 const uint64_t pictureID) const { | 310 const uint64_t pictureID) const { |
297 TRACE_EVENT1("webrtc", "RequestSLI", "picture_id", pictureID); | 311 TRACE_EVENT1("webrtc", "RequestSLI", "picture_id", pictureID); |
298 rtc::CritScope cs(&process_crit_); | 312 rtc::CritScope cs(&process_crit_); |
299 if (_frameTypeCallback != nullptr) { | 313 if (_frameTypeCallback != nullptr) { |
300 const int32_t ret = | 314 const int32_t ret = |
301 _frameTypeCallback->SliceLossIndicationRequest(pictureID); | 315 _frameTypeCallback->SliceLossIndicationRequest(pictureID); |
302 if (ret < 0) { | 316 if (ret < 0) { |
303 return ret; | 317 return ret; |
304 } | 318 } |
(...skipping 15 matching lines...) Expand all Loading... |
320 } else { | 334 } else { |
321 return VCM_MISSING_CALLBACK; | 335 return VCM_MISSING_CALLBACK; |
322 } | 336 } |
323 return VCM_OK; | 337 return VCM_OK; |
324 } | 338 } |
325 | 339 |
326 // Must be called from inside the receive side critical section. | 340 // Must be called from inside the receive side critical section. |
327 int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) { | 341 int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) { |
328 TRACE_EVENT0("webrtc", "VideoReceiver::Decode"); | 342 TRACE_EVENT0("webrtc", "VideoReceiver::Decode"); |
329 // Change decoder if payload type has changed | 343 // Change decoder if payload type has changed |
330 _decoder = _codecDataBase.GetDecoder(frame, &_decodedFrameCallback); | 344 VCMGenericDecoder* decoder = |
331 if (_decoder == nullptr) { | 345 _codecDataBase.GetDecoder(frame, &_decodedFrameCallback); |
| 346 if (decoder == nullptr) { |
332 return VCM_NO_CODEC_REGISTERED; | 347 return VCM_NO_CODEC_REGISTERED; |
333 } | 348 } |
334 // Decode a frame | 349 // Decode a frame |
335 int32_t ret = _decoder->Decode(frame, clock_->TimeInMilliseconds()); | 350 int32_t ret = decoder->Decode(frame, clock_->TimeInMilliseconds()); |
336 | 351 |
337 // Check for failed decoding, run frame type request callback if needed. | 352 // Check for failed decoding, run frame type request callback if needed. |
338 bool request_key_frame = false; | 353 bool request_key_frame = false; |
339 if (ret < 0) { | 354 if (ret < 0) { |
340 if (ret == VCM_ERROR_REQUEST_SLI) { | 355 if (ret == VCM_ERROR_REQUEST_SLI) { |
341 return RequestSliceLossIndication( | 356 return RequestSliceLossIndication( |
342 _decodedFrameCallback.LastReceivedPictureID() + 1); | 357 _decodedFrameCallback.LastReceivedPictureID() + 1); |
343 } else { | 358 } else { |
344 request_key_frame = true; | 359 request_key_frame = true; |
345 } | 360 } |
346 } else if (ret == VCM_REQUEST_SLI) { | 361 } else if (ret == VCM_REQUEST_SLI) { |
347 ret = RequestSliceLossIndication( | 362 ret = RequestSliceLossIndication( |
348 _decodedFrameCallback.LastReceivedPictureID() + 1); | 363 _decodedFrameCallback.LastReceivedPictureID() + 1); |
349 } | 364 } |
350 if (!frame.Complete() || frame.MissingFrame()) { | 365 if (!frame.Complete() || frame.MissingFrame()) { |
351 request_key_frame = true; | 366 request_key_frame = true; |
352 ret = VCM_OK; | 367 ret = VCM_OK; |
353 } | 368 } |
354 if (request_key_frame) { | 369 if (request_key_frame) { |
355 rtc::CritScope cs(&process_crit_); | 370 rtc::CritScope cs(&process_crit_); |
356 _scheduleKeyRequest = true; | 371 _scheduleKeyRequest = true; |
357 } | 372 } |
358 return ret; | 373 return ret; |
359 } | 374 } |
360 | 375 |
361 // Register possible receive codecs, can be called multiple times | 376 // Register possible receive codecs, can be called multiple times |
362 int32_t VideoReceiver::RegisterReceiveCodec(const VideoCodec* receiveCodec, | 377 int32_t VideoReceiver::RegisterReceiveCodec(const VideoCodec* receiveCodec, |
363 int32_t numberOfCores, | 378 int32_t numberOfCores, |
364 bool requireKeyFrame) { | 379 bool requireKeyFrame) { |
| 380 RTC_DCHECK(construction_thread_.CalledOnValidThread()); |
| 381 // TODO(tommi): This method must only be called when the decoder thread |
| 382 // is not running. Do we need a lock? If not, it looks like we might not need |
| 383 // a lock at all for |_codecDataBase|. |
365 rtc::CritScope cs(&receive_crit_); | 384 rtc::CritScope cs(&receive_crit_); |
366 if (receiveCodec == nullptr) { | 385 if (receiveCodec == nullptr) { |
367 return VCM_PARAMETER_ERROR; | 386 return VCM_PARAMETER_ERROR; |
368 } | 387 } |
369 if (!_codecDataBase.RegisterReceiveCodec(receiveCodec, numberOfCores, | 388 if (!_codecDataBase.RegisterReceiveCodec(receiveCodec, numberOfCores, |
370 requireKeyFrame)) { | 389 requireKeyFrame)) { |
371 return -1; | 390 return -1; |
372 } | 391 } |
373 return 0; | 392 return 0; |
374 } | 393 } |
375 | 394 |
376 // Get current received codec | 395 // Get current received codec |
| 396 // TODO(tommi): See if there are any actual callers to this method. |
| 397 // Neither me nor Stefan could find callers. If we can remove it, threading |
| 398 // will be simpler. |
377 int32_t VideoReceiver::ReceiveCodec(VideoCodec* currentReceiveCodec) const { | 399 int32_t VideoReceiver::ReceiveCodec(VideoCodec* currentReceiveCodec) const { |
378 rtc::CritScope cs(&receive_crit_); | 400 rtc::CritScope cs(&receive_crit_); |
379 if (currentReceiveCodec == nullptr) { | 401 if (currentReceiveCodec == nullptr) { |
380 return VCM_PARAMETER_ERROR; | 402 return VCM_PARAMETER_ERROR; |
381 } | 403 } |
382 return _codecDataBase.ReceiveCodec(currentReceiveCodec) ? 0 : -1; | 404 return _codecDataBase.ReceiveCodec(currentReceiveCodec) ? 0 : -1; |
383 } | 405 } |
384 | 406 |
385 // Get current received codec | 407 // Get current received codec |
| 408 // TODO(tommi): See if there are any actual callers to this method. |
| 409 // If not, it will make threading simpler. |
386 VideoCodecType VideoReceiver::ReceiveCodec() const { | 410 VideoCodecType VideoReceiver::ReceiveCodec() const { |
387 rtc::CritScope cs(&receive_crit_); | 411 rtc::CritScope cs(&receive_crit_); |
388 return _codecDataBase.ReceiveCodec(); | 412 return _codecDataBase.ReceiveCodec(); |
389 } | 413 } |
390 | 414 |
391 // Incoming packet from network parsed and ready for decode, non blocking. | 415 // Incoming packet from network parsed and ready for decode, non blocking. |
392 int32_t VideoReceiver::IncomingPacket(const uint8_t* incomingPayload, | 416 int32_t VideoReceiver::IncomingPacket(const uint8_t* incomingPayload, |
393 size_t payloadLength, | 417 size_t payloadLength, |
394 const WebRtcRTPHeader& rtpInfo) { | 418 const WebRtcRTPHeader& rtpInfo) { |
395 if (rtpInfo.frameType == kVideoFrameKey) { | 419 if (rtpInfo.frameType == kVideoFrameKey) { |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 _receiver.SetNackSettings(max_nack_list_size, max_packet_age_to_nack, | 520 _receiver.SetNackSettings(max_nack_list_size, max_packet_age_to_nack, |
497 max_incomplete_time_ms); | 521 max_incomplete_time_ms); |
498 } | 522 } |
499 | 523 |
500 int VideoReceiver::SetMinReceiverDelay(int desired_delay_ms) { | 524 int VideoReceiver::SetMinReceiverDelay(int desired_delay_ms) { |
501 return _receiver.SetMinReceiverDelay(desired_delay_ms); | 525 return _receiver.SetMinReceiverDelay(desired_delay_ms); |
502 } | 526 } |
503 | 527 |
504 } // namespace vcm | 528 } // namespace vcm |
505 } // namespace webrtc | 529 } // namespace webrtc |
OLD | NEW |