1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <assert.h>
12
13#include "webrtc/engine_configurations.h"
14#include "webrtc/modules/video_render/external/video_render_external_impl.h"
15#include "webrtc/modules/video_render/include/video_render_defines.h"
16#include "webrtc/modules/video_render/incoming_video_stream.h"
17#include "webrtc/modules/video_render/i_video_render.h"
18#include "webrtc/modules/video_render/video_render_impl.h"
19#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
20#include "webrtc/system_wrappers/interface/trace.h"
21
22namespace webrtc {
23
24VideoRender*
25VideoRender::CreateVideoRender(const int32_t id,
26                               void* window,
27                               const bool fullscreen,
28                               const VideoRenderType videoRenderType/*=kRenderDefault*/)
29{
30    VideoRenderType resultVideoRenderType = videoRenderType;
31    if (videoRenderType == kRenderDefault)
32    {
33        resultVideoRenderType = kRenderExternal;
34    }
35    return new ModuleVideoRenderImpl(id, resultVideoRenderType, window,
36                                     fullscreen);
37}
38
39void VideoRender::DestroyVideoRender(
40                                                         VideoRender* module)
41{
42    if (module)
43    {
44        delete module;
45    }
46}
47
48ModuleVideoRenderImpl::ModuleVideoRenderImpl(
49                                             const int32_t id,
50                                             const VideoRenderType videoRenderType,
51                                             void* window,
52                                             const bool fullscreen) :
53    _id(id), _moduleCrit(*CriticalSectionWrapper::CreateCriticalSection()),
54    _ptrWindow(window), _fullScreen(fullscreen), _ptrRenderer(NULL)
55{
56
57    // Create platform specific renderer
58    switch (videoRenderType)
59    {
60        case kRenderExternal:
61        {
62            VideoRenderExternalImpl* ptrRenderer(NULL);
63            ptrRenderer = new VideoRenderExternalImpl(_id, videoRenderType,
64                                                      window, _fullScreen);
65            if (ptrRenderer)
66            {
67                _ptrRenderer = reinterpret_cast<IVideoRender*> (ptrRenderer);
68            }
69        }
70            break;
71        default:
72            // Error...
73            break;
74    }
75    if (_ptrRenderer)
76    {
77        if (_ptrRenderer->Init() == -1)
78        {
79        }
80    }
81}
82
83ModuleVideoRenderImpl::~ModuleVideoRenderImpl()
84{
85    delete &_moduleCrit;
86
87    for (IncomingVideoStreamMap::iterator it = _streamRenderMap.begin();
88         it != _streamRenderMap.end();
89         ++it) {
90      delete it->second;
91    }
92
93    // Delete platform specific renderer
94    if (_ptrRenderer)
95    {
96        VideoRenderType videoRenderType = _ptrRenderer->RenderType();
97
98        switch (videoRenderType)
99        {
100            case kRenderExternal:
101            {
102                VideoRenderExternalImpl
103                        * ptrRenderer =
104                                reinterpret_cast<VideoRenderExternalImpl*> (_ptrRenderer);
105                _ptrRenderer = NULL;
106                delete ptrRenderer;
107            }
108            break;
109
110            default:
111                // Error...
112                break;
113        }
114    }
115}
116
117int32_t ModuleVideoRenderImpl::ChangeUniqueId(const int32_t id)
118{
119
120    CriticalSectionScoped cs(&_moduleCrit);
121
122    _id = id;
123
124    if (_ptrRenderer)
125    {
126        _ptrRenderer->ChangeUniqueId(_id);
127    }
128
129    return 0;
130}
131
132int32_t ModuleVideoRenderImpl::TimeUntilNextProcess()
133{
134    // Not used
135    return 50;
136}
137int32_t ModuleVideoRenderImpl::Process()
138{
139    // Not used
140    return 0;
141}
142
143void*
144ModuleVideoRenderImpl::Window()
145{
146    CriticalSectionScoped cs(&_moduleCrit);
147    return _ptrWindow;
148}
149
150int32_t ModuleVideoRenderImpl::ChangeWindow(void* window)
151{
152    return -1;
153}
154
155int32_t ModuleVideoRenderImpl::Id()
156{
157    CriticalSectionScoped cs(&_moduleCrit);
158    return _id;
159}
160
161uint32_t ModuleVideoRenderImpl::GetIncomingFrameRate(const uint32_t streamId) {
162  CriticalSectionScoped cs(&_moduleCrit);
163
164  IncomingVideoStreamMap::iterator it = _streamRenderMap.find(streamId);
165
166  if (it == _streamRenderMap.end()) {
167    // This stream doesn't exist
168    WEBRTC_TRACE(kTraceError,
169                 kTraceVideoRenderer,
170                 _id,
171                 "%s: stream doesn't exist",
172                 __FUNCTION__);
173    return 0;
174  }
175  assert(it->second != NULL);
176  return it->second->IncomingRate();
177}
178
179VideoRenderCallback*
180ModuleVideoRenderImpl::AddIncomingRenderStream(const uint32_t streamId,
181                                               const uint32_t zOrder,
182                                               const float left,
183                                               const float top,
184                                               const float right,
185                                               const float bottom)
186{
187    CriticalSectionScoped cs(&_moduleCrit);
188
189    if (!_ptrRenderer)
190    {
191        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
192                     "%s: No renderer", __FUNCTION__);
193        return NULL;
194    }
195
196    if (_streamRenderMap.find(streamId) != _streamRenderMap.end()) {
197        // The stream already exists...
198        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
199                     "%s: stream already exists", __FUNCTION__);
200        return NULL;
201    }
202
203    VideoRenderCallback* ptrRenderCallback =
204            _ptrRenderer->AddIncomingRenderStream(streamId, zOrder, left, top,
205                                                  right, bottom);
206    if (ptrRenderCallback == NULL)
207    {
208        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
209                     "%s: Can't create incoming stream in renderer",
210                     __FUNCTION__);
211        return NULL;
212    }
213
214    // Create platform independant code
215    IncomingVideoStream* ptrIncomingStream = new IncomingVideoStream(_id,
216                                                                     streamId);
217    if (ptrIncomingStream == NULL)
218    {
219        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
220                     "%s: Can't create incoming stream", __FUNCTION__);
221        return NULL;
222    }
223
224
225    if (ptrIncomingStream->SetRenderCallback(ptrRenderCallback) == -1)
226    {
227        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
228                     "%s: Can't set render callback", __FUNCTION__);
229        delete ptrIncomingStream;
230        _ptrRenderer->DeleteIncomingRenderStream(streamId);
231        return NULL;
232    }
233
234    VideoRenderCallback* moduleCallback =
235            ptrIncomingStream->ModuleCallback();
236
237    // Store the stream
238    _streamRenderMap[streamId] = ptrIncomingStream;
239
240    return moduleCallback;
241}
242
243int32_t ModuleVideoRenderImpl::DeleteIncomingRenderStream(
244                                                                const uint32_t streamId)
245{
246    CriticalSectionScoped cs(&_moduleCrit);
247
248    if (!_ptrRenderer)
249    {
250        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
251                     "%s: No renderer", __FUNCTION__);
252        return -1;
253    }
254
255    IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
256    if (item == _streamRenderMap.end())
257    {
258        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
259                     "%s: stream doesn't exist", __FUNCTION__);
260        return -1;
261    }
262
263    delete item->second;
264
265    _ptrRenderer->DeleteIncomingRenderStream(streamId);
266
267    _streamRenderMap.erase(item);
268
269    return 0;
270}
271
272int32_t ModuleVideoRenderImpl::AddExternalRenderCallback(
273    const uint32_t streamId,
274    VideoRenderCallback* renderObject) {
275    CriticalSectionScoped cs(&_moduleCrit);
276
277    IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
278
279    if (item == _streamRenderMap.end())
280    {
281        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
282                     "%s: stream doesn't exist", __FUNCTION__);
283        return -1;
284    }
285
286    if (item->second == NULL) {
287        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
288                     "%s: could not get stream", __FUNCTION__);
289        return -1;
290    }
291    return item->second->SetExternalCallback(renderObject);
292}
293
294int32_t ModuleVideoRenderImpl::GetIncomingRenderStreamProperties(
295    const uint32_t streamId,
296    uint32_t& zOrder,
297    float& left,
298    float& top,
299    float& right,
300    float& bottom) const {
301    CriticalSectionScoped cs(&_moduleCrit);
302
303    if (!_ptrRenderer)
304    {
305        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
306                     "%s: No renderer", __FUNCTION__);
307        return -1;
308    }
309
310    return _ptrRenderer->GetIncomingRenderStreamProperties(streamId, zOrder,
311                                                           left, top, right,
312                                                           bottom);
313}
314
315uint32_t ModuleVideoRenderImpl::GetNumIncomingRenderStreams() const
316{
317    CriticalSectionScoped cs(&_moduleCrit);
318
319    return static_cast<uint32_t>(_streamRenderMap.size());
320}
321
322bool ModuleVideoRenderImpl::HasIncomingRenderStream(
323    const uint32_t streamId) const {
324  CriticalSectionScoped cs(&_moduleCrit);
325
326  return _streamRenderMap.find(streamId) != _streamRenderMap.end();
327}
328
329int32_t ModuleVideoRenderImpl::RegisterRawFrameCallback(
330    const uint32_t streamId,
331    VideoRenderCallback* callbackObj) {
332  return -1;
333}
334
335int32_t ModuleVideoRenderImpl::StartRender(const uint32_t streamId)
336{
337    CriticalSectionScoped cs(&_moduleCrit);
338
339    if (!_ptrRenderer)
340    {
341        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
342                     "%s: No renderer", __FUNCTION__);
343        return -1;
344    }
345
346    // Start the stream
347    IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
348
349    if (item == _streamRenderMap.end())
350    {
351        return -1;
352    }
353
354    if (item->second->Start() == -1)
355    {
356        return -1;
357    }
358
359    // Start the HW renderer
360    if (_ptrRenderer->StartRender() == -1)
361    {
362        return -1;
363    }
364    return 0;
365}
366
367int32_t ModuleVideoRenderImpl::StopRender(const uint32_t streamId)
368{
369    CriticalSectionScoped cs(&_moduleCrit);
370
371    if (!_ptrRenderer)
372    {
373        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
374                     "%s(%d): No renderer", __FUNCTION__, streamId);
375        return -1;
376    }
377
378    // Stop the incoming stream
379    IncomingVideoStreamMap::iterator item = _streamRenderMap.find(streamId);
380
381    if (item == _streamRenderMap.end())
382    {
383        return -1;
384    }
385
386    if (item->second->Stop() == -1)
387    {
388        return -1;
389    }
390
391    return 0;
392}
393
394int32_t ModuleVideoRenderImpl::ResetRender()
395{
396    CriticalSectionScoped cs(&_moduleCrit);
397
398    int32_t ret = 0;
399    // Loop through all incoming streams and reset them
400    for (IncomingVideoStreamMap::iterator it = _streamRenderMap.begin();
401         it != _streamRenderMap.end();
402         ++it) {
403      if (it->second->Reset() == -1)
404        ret = -1;
405    }
406    return ret;
407}
408
409RawVideoType ModuleVideoRenderImpl::PreferredVideoType() const
410{
411    CriticalSectionScoped cs(&_moduleCrit);
412
413    if (_ptrRenderer == NULL)
414    {
415        return kVideoI420;
416    }
417
418    return _ptrRenderer->PerferedVideoType();
419}
420
421bool ModuleVideoRenderImpl::IsFullScreen()
422{
423    CriticalSectionScoped cs(&_moduleCrit);
424
425    if (!_ptrRenderer)
426    {
427        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
428                     "%s: No renderer", __FUNCTION__);
429        return false;
430    }
431    return _ptrRenderer->FullScreen();
432}
433
434int32_t ModuleVideoRenderImpl::GetScreenResolution(
435                                                         uint32_t& screenWidth,
436                                                         uint32_t& screenHeight) const
437{
438    CriticalSectionScoped cs(&_moduleCrit);
439
440    if (!_ptrRenderer)
441    {
442        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
443                     "%s: No renderer", __FUNCTION__);
444        return false;
445    }
446    return _ptrRenderer->GetScreenResolution(screenWidth, screenHeight);
447}
448
449uint32_t ModuleVideoRenderImpl::RenderFrameRate(
450                                                      const uint32_t streamId)
451{
452    CriticalSectionScoped cs(&_moduleCrit);
453
454    if (!_ptrRenderer)
455    {
456        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
457                     "%s: No renderer", __FUNCTION__);
458        return false;
459    }
460    return _ptrRenderer->RenderFrameRate(streamId);
461}
462
463int32_t ModuleVideoRenderImpl::SetStreamCropping(
464                                                       const uint32_t streamId,
465                                                       const float left,
466                                                       const float top,
467                                                       const float right,
468                                                       const float bottom)
469{
470    CriticalSectionScoped cs(&_moduleCrit);
471
472    if (!_ptrRenderer)
473    {
474        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
475                     "%s: No renderer", __FUNCTION__);
476        return false;
477    }
478    return _ptrRenderer->SetStreamCropping(streamId, left, top, right, bottom);
479}
480
481int32_t ModuleVideoRenderImpl::SetTransparentBackground(const bool enable)
482{
483    CriticalSectionScoped cs(&_moduleCrit);
484
485    if (!_ptrRenderer)
486    {
487        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
488                     "%s: No renderer", __FUNCTION__);
489        return false;
490    }
491    return _ptrRenderer->SetTransparentBackground(enable);
492}
493
494int32_t ModuleVideoRenderImpl::FullScreenRender(void* window, const bool enable)
495{
496    return -1;
497}
498
499int32_t ModuleVideoRenderImpl::SetText(
500                                             const uint8_t textId,
501                                             const uint8_t* text,
502                                             const int32_t textLength,
503                                             const uint32_t textColorRef,
504                                             const uint32_t backgroundColorRef,
505                                             const float left, const float top,
506                                             const float right,
507                                             const float bottom)
508{
509    CriticalSectionScoped cs(&_moduleCrit);
510
511    if (!_ptrRenderer)
512    {
513        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
514                     "%s: No renderer", __FUNCTION__);
515        return -1;
516    }
517    return _ptrRenderer->SetText(textId, text, textLength, textColorRef,
518                                 backgroundColorRef, left, top, right, bottom);
519}
520
521int32_t ModuleVideoRenderImpl::SetBitmap(const void* bitMap,
522                                         const uint8_t pictureId,
523                                         const void* colorKey,
524                                         const float left,
525                                         const float top,
526                                         const float right,
527                                         const float bottom)
528{
529    CriticalSectionScoped cs(&_moduleCrit);
530
531    if (!_ptrRenderer)
532    {
533        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
534                     "%s: No renderer", __FUNCTION__);
535        return -1;
536    }
537    return _ptrRenderer->SetBitmap(bitMap, pictureId, colorKey, left, top,
538                                   right, bottom);
539}
540
541int32_t ModuleVideoRenderImpl::GetLastRenderedFrame(
542    const uint32_t streamId,
543    I420VideoFrame &frame) const
544{
545    CriticalSectionScoped cs(&_moduleCrit);
546
547    if (!_ptrRenderer)
548    {
549        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
550                     "%s: No renderer", __FUNCTION__);
551        return -1;
552    }
553
554    IncomingVideoStreamMap::const_iterator item =
555        _streamRenderMap.find(streamId);
556    if (item == _streamRenderMap.end())
557    {
558        // This stream doesn't exist
559        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
560                     "%s: stream doesn't exist", __FUNCTION__);
561        return 0;
562    }
563
564    assert(item->second != NULL);
565    return item->second->GetLastRenderedFrame(frame);
566}
567
568int32_t ModuleVideoRenderImpl::SetExpectedRenderDelay(
569    uint32_t stream_id, int32_t delay_ms) {
570  CriticalSectionScoped cs(&_moduleCrit);
571
572  if (!_ptrRenderer) {
573    WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
574                 "%s: No renderer", __FUNCTION__);
575    return false;
576  }
577
578  IncomingVideoStreamMap::const_iterator item =
579      _streamRenderMap.find(stream_id);
580  if (item == _streamRenderMap.end()) {
581    // This stream doesn't exist
582    WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
583                 "%s(%u, %d): stream doesn't exist", __FUNCTION__, stream_id,
584                 delay_ms);
585    return -1;
586  }
587
588  assert(item->second != NULL);
589  return item->second->SetExpectedRenderDelay(delay_ms);
590}
591
592int32_t ModuleVideoRenderImpl::ConfigureRenderer(
593                                                       const uint32_t streamId,
594                                                       const unsigned int zOrder,
595                                                       const float left,
596                                                       const float top,
597                                                       const float right,
598                                                       const float bottom)
599{
600    CriticalSectionScoped cs(&_moduleCrit);
601
602    if (!_ptrRenderer)
603    {
604        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
605                     "%s: No renderer", __FUNCTION__);
606        return false;
607    }
608    return _ptrRenderer->ConfigureRenderer(streamId, zOrder, left, top, right,
609                                           bottom);
610}
611
612int32_t ModuleVideoRenderImpl::SetStartImage(
613    const uint32_t streamId,
614    const I420VideoFrame& videoFrame)
615{
616    CriticalSectionScoped cs(&_moduleCrit);
617
618    if (!_ptrRenderer)
619    {
620        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
621                     "%s: No renderer", __FUNCTION__);
622        return -1;
623    }
624
625    IncomingVideoStreamMap::const_iterator item =
626        _streamRenderMap.find(streamId);
627    if (item == _streamRenderMap.end())
628    {
629        // This stream doesn't exist
630        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
631                     "%s: stream doesn't exist", __FUNCTION__);
632        return -1;
633    }
634    assert (item->second != NULL);
635    return item->second->SetStartImage(videoFrame);
636
637}
638
639int32_t ModuleVideoRenderImpl::SetTimeoutImage(
640    const uint32_t streamId,
641    const I420VideoFrame& videoFrame,
642    const uint32_t timeout)
643{
644    CriticalSectionScoped cs(&_moduleCrit);
645
646    if (!_ptrRenderer)
647    {
648        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
649                     "%s: No renderer", __FUNCTION__);
650        return -1;
651    }
652
653    IncomingVideoStreamMap::const_iterator item =
654        _streamRenderMap.find(streamId);
655    if (item == _streamRenderMap.end())
656    {
657        // This stream doesn't exist
658        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
659                     "%s: stream doesn't exist", __FUNCTION__);
660        return -1;
661    }
662    assert(item->second != NULL);
663    return item->second->SetTimeoutImage(videoFrame, timeout);
664}
665
666int32_t ModuleVideoRenderImpl::MirrorRenderStream(const int renderId,
667                                                  const bool enable,
668                                                  const bool mirrorXAxis,
669                                                  const bool mirrorYAxis)
670{
671    CriticalSectionScoped cs(&_moduleCrit);
672
673    if (!_ptrRenderer)
674    {
675        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
676                     "%s: No renderer", __FUNCTION__);
677        return -1;
678    }
679
680    IncomingVideoStreamMap::const_iterator item =
681        _streamRenderMap.find(renderId);
682    if (item == _streamRenderMap.end())
683    {
684        // This stream doesn't exist
685        WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
686                     "%s: stream doesn't exist", __FUNCTION__);
687        return 0;
688    }
689    assert(item->second != NULL);
690
691    return item->second->EnableMirroring(enable, mirrorXAxis, mirrorYAxis);
692}
693
694}  // namespace webrtc
695