Home | History | Annotate | Download | only in testAPI
      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 "webrtc/modules/video_render/test/testAPI/testAPI.h"
     12 
     13 #include <stdio.h>
     14 
     15 #if defined(_WIN32)
     16 #include <tchar.h>
     17 #include <windows.h>
     18 #include <assert.h>
     19 #include <fstream>
     20 #include <iostream>
     21 #include <string>
     22 #include <windows.h>
     23 #include <ddraw.h>
     24 
     25 #elif defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
     26 
     27 #include <X11/Xlib.h>
     28 #include <X11/Xutil.h>
     29 #include <iostream>
     30 #include <sys/time.h>
     31 
     32 #endif
     33 
     34 #include "webrtc/common_types.h"
     35 #include "webrtc/modules/interface/module_common_types.h"
     36 #include "webrtc/modules/utility/interface/process_thread.h"
     37 #include "webrtc/modules/video_render/include/video_render.h"
     38 #include "webrtc/modules/video_render/include/video_render_defines.h"
     39 #include "webrtc/system_wrappers/interface/sleep.h"
     40 #include "webrtc/system_wrappers/interface/tick_util.h"
     41 #include "webrtc/system_wrappers/interface/trace.h"
     42 
     43 using namespace webrtc;
     44 
     45 void GetTestVideoFrame(I420VideoFrame* frame,
     46                        uint8_t startColor);
     47 int TestSingleStream(VideoRender* renderModule);
     48 int TestFullscreenStream(VideoRender* &renderModule,
     49                          void* window,
     50                          const VideoRenderType videoRenderType);
     51 int TestBitmapText(VideoRender* renderModule);
     52 int TestMultipleStreams(VideoRender* renderModule);
     53 int TestExternalRender(VideoRender* renderModule);
     54 
     55 #define TEST_FRAME_RATE 30
     56 #define TEST_TIME_SECOND 5
     57 #define TEST_FRAME_NUM (TEST_FRAME_RATE*TEST_TIME_SECOND)
     58 #define TEST_STREAM0_START_COLOR 0
     59 #define TEST_STREAM1_START_COLOR 64
     60 #define TEST_STREAM2_START_COLOR 128
     61 #define TEST_STREAM3_START_COLOR 192
     62 
     63 #if defined(WEBRTC_LINUX)
     64 
     65 #define GET_TIME_IN_MS timeGetTime()
     66 
     67 unsigned long timeGetTime()
     68 {
     69     struct timeval tv;
     70     struct timezone tz;
     71     unsigned long val;
     72 
     73     gettimeofday(&tv, &tz);
     74     val= tv.tv_sec*1000+ tv.tv_usec/1000;
     75     return(val);
     76 }
     77 
     78 #elif defined(WEBRTC_MAC)
     79 
     80 #include <unistd.h>
     81 
     82 #define GET_TIME_IN_MS timeGetTime()
     83 
     84 unsigned long timeGetTime()
     85 {
     86     return 0;
     87 }
     88 
     89 #else
     90 
     91 #define GET_TIME_IN_MS ::timeGetTime()
     92 
     93 #endif
     94 
     95 using namespace std;
     96 
     97 #if defined(_WIN32)
     98 LRESULT CALLBACK WebRtcWinProc( HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
     99 {
    100     switch(uMsg)
    101     {
    102         case WM_DESTROY:
    103         break;
    104         case WM_COMMAND:
    105         break;
    106     }
    107     return DefWindowProc(hWnd,uMsg,wParam,lParam);
    108 }
    109 
    110 int WebRtcCreateWindow(HWND &hwndMain,int winNum, int width, int height)
    111 {
    112     HINSTANCE hinst = GetModuleHandle(0);
    113     WNDCLASSEX wcx;
    114     wcx.hInstance = hinst;
    115     wcx.lpszClassName = TEXT("VideoRenderTest");
    116     wcx.lpfnWndProc = (WNDPROC)WebRtcWinProc;
    117     wcx.style = CS_DBLCLKS;
    118     wcx.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    119     wcx.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    120     wcx.hCursor = LoadCursor (NULL, IDC_ARROW);
    121     wcx.lpszMenuName = NULL;
    122     wcx.cbSize = sizeof (WNDCLASSEX);
    123     wcx.cbClsExtra = 0;
    124     wcx.cbWndExtra = 0;
    125     wcx.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    126 
    127     // Register our window class with the operating system.
    128     // If there is an error, exit program.
    129     if ( !RegisterClassEx (&wcx) )
    130     {
    131         MessageBox( 0, TEXT("Failed to register window class!"),TEXT("Error!"), MB_OK|MB_ICONERROR );
    132         return 0;
    133     }
    134 
    135     // Create the main window.
    136     hwndMain = CreateWindowEx(
    137             0, // no extended styles
    138             TEXT("VideoRenderTest"), // class name
    139             TEXT("VideoRenderTest Window"), // window name
    140             WS_OVERLAPPED |WS_THICKFRAME, // overlapped window
    141             800, // horizontal position
    142             0, // vertical position
    143             width, // width
    144             height, // height
    145             (HWND) NULL, // no parent or owner window
    146             (HMENU) NULL, // class menu used
    147             hinst, // instance handle
    148             NULL); // no window creation data
    149 
    150     if (!hwndMain)
    151         return -1;
    152 
    153     // Show the window using the flag specified by the program
    154     // that started the application, and send the application
    155     // a WM_PAINT message.
    156 
    157     ShowWindow(hwndMain, SW_SHOWDEFAULT);
    158     UpdateWindow(hwndMain);
    159     return 0;
    160 }
    161 
    162 #elif defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
    163 
    164 int WebRtcCreateWindow(Window *outWindow, Display **outDisplay, int winNum, int width, int height) // unsigned char* title, int titleLength)
    165 
    166 {
    167     int screen, xpos = 10, ypos = 10;
    168     XEvent evnt;
    169     XSetWindowAttributes xswa; // window attribute struct
    170     XVisualInfo vinfo; // screen visual info struct
    171     unsigned long mask; // attribute mask
    172 
    173     // get connection handle to xserver
    174     Display* _display = XOpenDisplay( NULL );
    175 
    176     // get screen number
    177     screen = DefaultScreen(_display);
    178 
    179     // put desired visual info for the screen in vinfo
    180     if( XMatchVisualInfo(_display, screen, 24, TrueColor, &vinfo) != 0 )
    181     {
    182         //printf( "Screen visual info match!\n" );
    183     }
    184 
    185     // set window attributes
    186     xswa.colormap = XCreateColormap(_display, DefaultRootWindow(_display), vinfo.visual, AllocNone);
    187     xswa.event_mask = StructureNotifyMask | ExposureMask;
    188     xswa.background_pixel = 0;
    189     xswa.border_pixel = 0;
    190 
    191     // value mask for attributes
    192     mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
    193 
    194     switch( winNum )
    195     {
    196         case 0:
    197         xpos = 200;
    198         ypos = 200;
    199         break;
    200         case 1:
    201         xpos = 300;
    202         ypos = 200;
    203         break;
    204         default:
    205         break;
    206     }
    207 
    208     // create a subwindow for parent (defroot)
    209     Window _window = XCreateWindow(_display, DefaultRootWindow(_display),
    210             xpos, ypos,
    211             width,
    212             height,
    213             0, vinfo.depth,
    214             InputOutput,
    215             vinfo.visual,
    216             mask, &xswa);
    217 
    218     // Set window name
    219     if( winNum == 0 )
    220     {
    221         XStoreName(_display, _window, "VE MM Local Window");
    222         XSetIconName(_display, _window, "VE MM Local Window");
    223     }
    224     else if( winNum == 1 )
    225     {
    226         XStoreName(_display, _window, "VE MM Remote Window");
    227         XSetIconName(_display, _window, "VE MM Remote Window");
    228     }
    229 
    230     // make x report events for mask
    231     XSelectInput(_display, _window, StructureNotifyMask);
    232 
    233     // map the window to the display
    234     XMapWindow(_display, _window);
    235 
    236     // wait for map event
    237     do
    238     {
    239         XNextEvent(_display, &evnt);
    240     }
    241     while (evnt.type != MapNotify || evnt.xmap.event != _window);
    242 
    243     *outWindow = _window;
    244     *outDisplay = _display;
    245 
    246     return 0;
    247 }
    248 #endif  // LINUX
    249 
    250 // Note: Mac code is in testApi_mac.mm.
    251 
    252 class MyRenderCallback: public VideoRenderCallback
    253 {
    254 public:
    255     MyRenderCallback() :
    256         _cnt(0)
    257     {
    258     }
    259     ;
    260     ~MyRenderCallback()
    261     {
    262     }
    263     ;
    264     virtual int32_t RenderFrame(const uint32_t streamId,
    265                                 I420VideoFrame& videoFrame)
    266     {
    267         _cnt++;
    268         if (_cnt % 100 == 0)
    269         {
    270             printf("Render callback %d \n",_cnt);
    271         }
    272         return 0;
    273     }
    274     int32_t _cnt;
    275 };
    276 
    277 void GetTestVideoFrame(I420VideoFrame* frame,
    278                        uint8_t startColor) {
    279     // changing color
    280     static uint8_t color = startColor;
    281 
    282     memset(frame->buffer(kYPlane), color, frame->allocated_size(kYPlane));
    283     memset(frame->buffer(kUPlane), color, frame->allocated_size(kUPlane));
    284     memset(frame->buffer(kVPlane), color, frame->allocated_size(kVPlane));
    285 
    286     ++color;
    287 }
    288 
    289 int TestSingleStream(VideoRender* renderModule) {
    290     int error = 0;
    291     // Add settings for a stream to render
    292     printf("Add stream 0 to entire window\n");
    293     const int streamId0 = 0;
    294     VideoRenderCallback* renderCallback0 = renderModule->AddIncomingRenderStream(streamId0, 0, 0.0f, 0.0f, 1.0f, 1.0f);
    295     assert(renderCallback0 != NULL);
    296 
    297 #ifndef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
    298     MyRenderCallback externalRender;
    299     renderModule->AddExternalRenderCallback(streamId0, &externalRender);
    300 #endif
    301 
    302     printf("Start render\n");
    303     error = renderModule->StartRender(streamId0);
    304     if (error != 0) {
    305       // TODO(phoglund): This test will not work if compiled in release mode.
    306       // This rather silly construct here is to avoid compilation errors when
    307       // compiling in release. Release => no asserts => unused 'error' variable.
    308       assert(false);
    309     }
    310 
    311     // Loop through an I420 file and render each frame
    312     const int width = 352;
    313     const int half_width = (width + 1) / 2;
    314     const int height = 288;
    315 
    316     I420VideoFrame videoFrame0;
    317     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
    318 
    319     const uint32_t renderDelayMs = 500;
    320 
    321     for (int i=0; i<TEST_FRAME_NUM; i++) {
    322         GetTestVideoFrame(&videoFrame0, TEST_STREAM0_START_COLOR);
    323         // Render this frame with the specified delay
    324         videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp()
    325                                        + renderDelayMs);
    326         renderCallback0->RenderFrame(streamId0, videoFrame0);
    327         SleepMs(1000/TEST_FRAME_RATE);
    328     }
    329 
    330 
    331     // Shut down
    332     printf("Closing...\n");
    333     error = renderModule->StopRender(streamId0);
    334     assert(error == 0);
    335 
    336     error = renderModule->DeleteIncomingRenderStream(streamId0);
    337     assert(error == 0);
    338 
    339     return 0;
    340 }
    341 
    342 int TestFullscreenStream(VideoRender* &renderModule,
    343                          void* window,
    344                          const VideoRenderType videoRenderType) {
    345     VideoRender::DestroyVideoRender(renderModule);
    346     renderModule = VideoRender::CreateVideoRender(12345, window, true, videoRenderType);
    347 
    348     TestSingleStream(renderModule);
    349 
    350     VideoRender::DestroyVideoRender(renderModule);
    351     renderModule = VideoRender::CreateVideoRender(12345, window, false, videoRenderType);
    352 
    353     return 0;
    354 }
    355 
    356 int TestBitmapText(VideoRender* renderModule) {
    357 #if defined(WIN32)
    358 
    359     int error = 0;
    360     // Add settings for a stream to render
    361     printf("Add stream 0 to entire window\n");
    362     const int streamId0 = 0;
    363     VideoRenderCallback* renderCallback0 = renderModule->AddIncomingRenderStream(streamId0, 0, 0.0f, 0.0f, 1.0f, 1.0f);
    364     assert(renderCallback0 != NULL);
    365 
    366     printf("Adding Bitmap\n");
    367     DDCOLORKEY ColorKey; // black
    368     ColorKey.dwColorSpaceHighValue = RGB(0, 0, 0);
    369     ColorKey.dwColorSpaceLowValue = RGB(0, 0, 0);
    370     HBITMAP hbm = (HBITMAP)LoadImage(NULL,
    371                                      (LPCTSTR)_T("renderStartImage.bmp"),
    372                                      IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    373     renderModule->SetBitmap(hbm, 0, &ColorKey, 0.0f, 0.0f, 0.3f,
    374                              0.3f);
    375 
    376     printf("Adding Text\n");
    377     renderModule->SetText(1, (uint8_t*) "WebRtc Render Demo App", 20,
    378                            RGB(255, 0, 0), RGB(0, 0, 0), 0.25f, 0.1f, 1.0f,
    379                            1.0f);
    380 
    381     printf("Start render\n");
    382     error = renderModule->StartRender(streamId0);
    383     assert(error == 0);
    384 
    385     // Loop through an I420 file and render each frame
    386     const int width = 352;
    387     const int half_width = (width + 1) / 2;
    388     const int height = 288;
    389 
    390     I420VideoFrame videoFrame0;
    391     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
    392 
    393     const uint32_t renderDelayMs = 500;
    394 
    395     for (int i=0; i<TEST_FRAME_NUM; i++) {
    396         GetTestVideoFrame(&videoFrame0, TEST_STREAM0_START_COLOR);
    397         // Render this frame with the specified delay
    398         videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp() +
    399                                        renderDelayMs);
    400         renderCallback0->RenderFrame(streamId0, videoFrame0);
    401         SleepMs(1000/TEST_FRAME_RATE);
    402     }
    403     // Sleep and let all frames be rendered before closing
    404     SleepMs(renderDelayMs*2);
    405 
    406 
    407     // Shut down
    408     printf("Closing...\n");
    409     ColorKey.dwColorSpaceHighValue = RGB(0,0,0);
    410     ColorKey.dwColorSpaceLowValue = RGB(0,0,0);
    411     renderModule->SetBitmap(NULL, 0, &ColorKey, 0.0f, 0.0f, 0.0f, 0.0f);
    412     renderModule->SetText(1, NULL, 20, RGB(255,255,255),
    413                     RGB(0,0,0), 0.0f, 0.0f, 0.0f, 0.0f);
    414 
    415     error = renderModule->StopRender(streamId0);
    416     assert(error == 0);
    417 
    418     error = renderModule->DeleteIncomingRenderStream(streamId0);
    419     assert(error == 0);
    420 #endif
    421 
    422     return 0;
    423 }
    424 
    425 int TestMultipleStreams(VideoRender* renderModule) {
    426     int error = 0;
    427 
    428     // Add settings for a stream to render
    429     printf("Add stream 0\n");
    430     const int streamId0 = 0;
    431     VideoRenderCallback* renderCallback0 =
    432         renderModule->AddIncomingRenderStream(streamId0, 0, 0.0f, 0.0f, 0.45f, 0.45f);
    433     assert(renderCallback0 != NULL);
    434     printf("Add stream 1\n");
    435     const int streamId1 = 1;
    436     VideoRenderCallback* renderCallback1 =
    437         renderModule->AddIncomingRenderStream(streamId1, 0, 0.55f, 0.0f, 1.0f, 0.45f);
    438     assert(renderCallback1 != NULL);
    439     printf("Add stream 2\n");
    440     const int streamId2 = 2;
    441     VideoRenderCallback* renderCallback2 =
    442         renderModule->AddIncomingRenderStream(streamId2, 0, 0.0f, 0.55f, 0.45f, 1.0f);
    443     assert(renderCallback2 != NULL);
    444     printf("Add stream 3\n");
    445     const int streamId3 = 3;
    446     VideoRenderCallback* renderCallback3 =
    447         renderModule->AddIncomingRenderStream(streamId3, 0, 0.55f, 0.55f, 1.0f, 1.0f);
    448     assert(renderCallback3 != NULL);
    449     error = renderModule->StartRender(streamId0);
    450     if (error != 0) {
    451       // TODO(phoglund): This test will not work if compiled in release mode.
    452       // This rather silly construct here is to avoid compilation errors when
    453       // compiling in release. Release => no asserts => unused 'error' variable.
    454       assert(false);
    455     }
    456     error = renderModule->StartRender(streamId1);
    457     assert(error == 0);
    458     error = renderModule->StartRender(streamId2);
    459     assert(error == 0);
    460     error = renderModule->StartRender(streamId3);
    461     assert(error == 0);
    462 
    463     // Loop through an I420 file and render each frame
    464     const int width = 352;
    465     const int half_width = (width + 1) / 2;
    466     const int height = 288;
    467 
    468     I420VideoFrame videoFrame0;
    469     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
    470     I420VideoFrame videoFrame1;
    471     videoFrame1.CreateEmptyFrame(width, height, width, half_width, half_width);
    472     I420VideoFrame videoFrame2;
    473     videoFrame2.CreateEmptyFrame(width, height, width, half_width, half_width);
    474     I420VideoFrame videoFrame3;
    475     videoFrame3.CreateEmptyFrame(width, height, width, half_width, half_width);
    476 
    477     const uint32_t renderDelayMs = 500;
    478 
    479     // Render frames with the specified delay.
    480     for (int i=0; i<TEST_FRAME_NUM; i++) {
    481       GetTestVideoFrame(&videoFrame0, TEST_STREAM0_START_COLOR);
    482 
    483       videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp() +
    484                                      renderDelayMs);
    485       renderCallback0->RenderFrame(streamId0, videoFrame0);
    486 
    487       GetTestVideoFrame(&videoFrame1, TEST_STREAM1_START_COLOR);
    488       videoFrame1.set_render_time_ms(TickTime::MillisecondTimestamp() +
    489                                      renderDelayMs);
    490       renderCallback1->RenderFrame(streamId1, videoFrame1);
    491 
    492       GetTestVideoFrame(&videoFrame2,  TEST_STREAM2_START_COLOR);
    493       videoFrame2.set_render_time_ms(TickTime::MillisecondTimestamp() +
    494                                      renderDelayMs);
    495       renderCallback2->RenderFrame(streamId2, videoFrame2);
    496 
    497       GetTestVideoFrame(&videoFrame3, TEST_STREAM3_START_COLOR);
    498       videoFrame3.set_render_time_ms(TickTime::MillisecondTimestamp() +
    499                                      renderDelayMs);
    500       renderCallback3->RenderFrame(streamId3, videoFrame3);
    501 
    502       SleepMs(1000/TEST_FRAME_RATE);
    503     }
    504 
    505     // Shut down
    506     printf("Closing...\n");
    507     error = renderModule->StopRender(streamId0);
    508     assert(error == 0);
    509     error = renderModule->DeleteIncomingRenderStream(streamId0);
    510     assert(error == 0);
    511     error = renderModule->StopRender(streamId1);
    512     assert(error == 0);
    513     error = renderModule->DeleteIncomingRenderStream(streamId1);
    514     assert(error == 0);
    515     error = renderModule->StopRender(streamId2);
    516     assert(error == 0);
    517     error = renderModule->DeleteIncomingRenderStream(streamId2);
    518     assert(error == 0);
    519     error = renderModule->StopRender(streamId3);
    520     assert(error == 0);
    521     error = renderModule->DeleteIncomingRenderStream(streamId3);
    522     assert(error == 0);
    523 
    524     return 0;
    525 }
    526 
    527 int TestExternalRender(VideoRender* renderModule) {
    528     int error = 0;
    529     MyRenderCallback *externalRender = new MyRenderCallback();
    530 
    531     const int streamId0 = 0;
    532     VideoRenderCallback* renderCallback0 =
    533         renderModule->AddIncomingRenderStream(streamId0, 0, 0.0f, 0.0f,
    534                                                    1.0f, 1.0f);
    535     assert(renderCallback0 != NULL);
    536     error = renderModule->AddExternalRenderCallback(streamId0, externalRender);
    537     if (error != 0) {
    538       // TODO(phoglund): This test will not work if compiled in release mode.
    539       // This rather silly construct here is to avoid compilation errors when
    540       // compiling in release. Release => no asserts => unused 'error' variable.
    541       assert(false);
    542     }
    543 
    544     error = renderModule->StartRender(streamId0);
    545     assert(error == 0);
    546 
    547     const int width = 352;
    548     const int half_width = (width + 1) / 2;
    549     const int height = 288;
    550     I420VideoFrame videoFrame0;
    551     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
    552 
    553     const uint32_t renderDelayMs = 500;
    554     int frameCount = TEST_FRAME_NUM;
    555     for (int i=0; i<frameCount; i++) {
    556         videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp() +
    557                                        renderDelayMs);
    558         renderCallback0->RenderFrame(streamId0, videoFrame0);
    559         SleepMs(33);
    560     }
    561 
    562     // Sleep and let all frames be rendered before closing
    563     SleepMs(2*renderDelayMs);
    564 
    565     // Shut down
    566     printf("Closing...\n");
    567     error = renderModule->StopRender(streamId0);
    568     assert(error == 0);
    569     error = renderModule->DeleteIncomingRenderStream(streamId0);
    570     assert(error == 0);
    571     assert(frameCount == externalRender->_cnt);
    572 
    573     delete externalRender;
    574     externalRender = NULL;
    575 
    576     return 0;
    577 }
    578 
    579 void RunVideoRenderTests(void* window, VideoRenderType windowType) {
    580 #ifndef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
    581     windowType = kRenderExternal;
    582 #endif
    583 
    584     int myId = 12345;
    585 
    586     // Create the render module
    587     printf("Create render module\n");
    588     VideoRender* renderModule = NULL;
    589     renderModule = VideoRender::CreateVideoRender(myId,
    590                                                   window,
    591                                                   false,
    592                                                   windowType);
    593     assert(renderModule != NULL);
    594 
    595     // ##### Test single stream rendering ####
    596     printf("#### TestSingleStream ####\n");
    597     if (TestSingleStream(renderModule) != 0) {
    598         printf ("TestSingleStream failed\n");
    599     }
    600 
    601     // ##### Test fullscreen rendering ####
    602     printf("#### TestFullscreenStream ####\n");
    603     if (TestFullscreenStream(renderModule, window, windowType) != 0) {
    604         printf ("TestFullscreenStream failed\n");
    605     }
    606 
    607     // ##### Test bitmap and text ####
    608     printf("#### TestBitmapText ####\n");
    609     if (TestBitmapText(renderModule) != 0) {
    610         printf ("TestBitmapText failed\n");
    611     }
    612 
    613     // ##### Test multiple streams ####
    614     printf("#### TestMultipleStreams ####\n");
    615     if (TestMultipleStreams(renderModule) != 0) {
    616         printf ("TestMultipleStreams failed\n");
    617     }
    618 
    619     // ##### Test multiple streams ####
    620     printf("#### TestExternalRender ####\n");
    621     if (TestExternalRender(renderModule) != 0) {
    622         printf ("TestExternalRender failed\n");
    623     }
    624 
    625     delete renderModule;
    626     renderModule = NULL;
    627 
    628     printf("VideoRender unit tests passed.\n");
    629 }
    630 
    631 // Note: The Mac main is implemented in testApi_mac.mm.
    632 #if defined(_WIN32)
    633 int _tmain(int argc, _TCHAR* argv[])
    634 #elif defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
    635 int main(int argc, char* argv[])
    636 #endif
    637 #if !defined(WEBRTC_MAC) && !defined(WEBRTC_ANDROID)
    638 {
    639     // Create a window for testing.
    640     void* window = NULL;
    641 #if defined (_WIN32)
    642     HWND testHwnd;
    643     WebRtcCreateWindow(testHwnd, 0, 352, 288);
    644     window = (void*)testHwnd;
    645     VideoRenderType windowType = kRenderWindows;
    646 #elif defined(WEBRTC_LINUX)
    647     Window testWindow;
    648     Display* display;
    649     WebRtcCreateWindow(&testWindow, &display, 0, 352, 288);
    650     VideoRenderType windowType = kRenderX11;
    651     window = (void*)testWindow;
    652 #endif // WEBRTC_LINUX
    653 
    654     RunVideoRenderTests(window, windowType);
    655     return 0;
    656 }
    657 #endif  // !WEBRTC_MAC
    658