Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / video_render / test / testAPI / testAPI.cc
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     printf("Start render\n");
298     error = renderModule->StartRender(streamId0);
299     if (error != 0) {
300       // TODO(phoglund): This test will not work if compiled in release mode.
301       // This rather silly construct here is to avoid compilation errors when
302       // compiling in release. Release => no asserts => unused 'error' variable.
303       assert(false);
304     }
305
306     // Loop through an I420 file and render each frame
307     const int width = 352;
308     const int half_width = (width + 1) / 2;
309     const int height = 288;
310
311     I420VideoFrame videoFrame0;
312     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
313
314     const uint32_t renderDelayMs = 500;
315
316     for (int i=0; i<TEST_FRAME_NUM; i++) {
317         GetTestVideoFrame(&videoFrame0, TEST_STREAM0_START_COLOR);
318         // Render this frame with the specified delay
319         videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp()
320                                        + renderDelayMs);
321         renderCallback0->RenderFrame(streamId0, videoFrame0);
322         SleepMs(1000/TEST_FRAME_RATE);
323     }
324
325
326     // Shut down
327     printf("Closing...\n");
328     error = renderModule->StopRender(streamId0);
329     assert(error == 0);
330
331     error = renderModule->DeleteIncomingRenderStream(streamId0);
332     assert(error == 0);
333
334     return 0;
335 }
336
337 int TestFullscreenStream(VideoRender* &renderModule,
338                          void* window,
339                          const VideoRenderType videoRenderType) {
340     VideoRender::DestroyVideoRender(renderModule);
341     renderModule = VideoRender::CreateVideoRender(12345, window, true, videoRenderType);
342
343     TestSingleStream(renderModule);
344
345     VideoRender::DestroyVideoRender(renderModule);
346     renderModule = VideoRender::CreateVideoRender(12345, window, false, videoRenderType);
347
348     return 0;
349 }
350
351 int TestBitmapText(VideoRender* renderModule) {
352 #if defined(WIN32)
353
354     int error = 0;
355     // Add settings for a stream to render
356     printf("Add stream 0 to entire window\n");
357     const int streamId0 = 0;
358     VideoRenderCallback* renderCallback0 = renderModule->AddIncomingRenderStream(streamId0, 0, 0.0f, 0.0f, 1.0f, 1.0f);
359     assert(renderCallback0 != NULL);
360
361     printf("Adding Bitmap\n");
362     DDCOLORKEY ColorKey; // black
363     ColorKey.dwColorSpaceHighValue = RGB(0, 0, 0);
364     ColorKey.dwColorSpaceLowValue = RGB(0, 0, 0);
365     HBITMAP hbm = (HBITMAP)LoadImage(NULL,
366                                      (LPCTSTR)_T("renderStartImage.bmp"),
367                                      IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
368     renderModule->SetBitmap(hbm, 0, &ColorKey, 0.0f, 0.0f, 0.3f,
369                              0.3f);
370
371     printf("Adding Text\n");
372     renderModule->SetText(1, (uint8_t*) "WebRtc Render Demo App", 20,
373                            RGB(255, 0, 0), RGB(0, 0, 0), 0.25f, 0.1f, 1.0f,
374                            1.0f);
375
376     printf("Start render\n");
377     error = renderModule->StartRender(streamId0);
378     assert(error == 0);
379
380     // Loop through an I420 file and render each frame
381     const int width = 352;
382     const int half_width = (width + 1) / 2;
383     const int height = 288;
384
385     I420VideoFrame videoFrame0;
386     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
387
388     const uint32_t renderDelayMs = 500;
389
390     for (int i=0; i<TEST_FRAME_NUM; i++) {
391         GetTestVideoFrame(&videoFrame0, TEST_STREAM0_START_COLOR);
392         // Render this frame with the specified delay
393         videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp() +
394                                        renderDelayMs);
395         renderCallback0->RenderFrame(streamId0, videoFrame0);
396         SleepMs(1000/TEST_FRAME_RATE);
397     }
398     // Sleep and let all frames be rendered before closing
399     SleepMs(renderDelayMs*2);
400
401
402     // Shut down
403     printf("Closing...\n");
404     ColorKey.dwColorSpaceHighValue = RGB(0,0,0);
405     ColorKey.dwColorSpaceLowValue = RGB(0,0,0);
406     renderModule->SetBitmap(NULL, 0, &ColorKey, 0.0f, 0.0f, 0.0f, 0.0f);
407     renderModule->SetText(1, NULL, 20, RGB(255,255,255),
408                     RGB(0,0,0), 0.0f, 0.0f, 0.0f, 0.0f);
409
410     error = renderModule->StopRender(streamId0);
411     assert(error == 0);
412
413     error = renderModule->DeleteIncomingRenderStream(streamId0);
414     assert(error == 0);
415 #endif
416
417     return 0;
418 }
419
420 int TestMultipleStreams(VideoRender* renderModule) {
421     int error = 0;
422
423     // Add settings for a stream to render
424     printf("Add stream 0\n");
425     const int streamId0 = 0;
426     VideoRenderCallback* renderCallback0 =
427         renderModule->AddIncomingRenderStream(streamId0, 0, 0.0f, 0.0f, 0.45f, 0.45f);
428     assert(renderCallback0 != NULL);
429     printf("Add stream 1\n");
430     const int streamId1 = 1;
431     VideoRenderCallback* renderCallback1 =
432         renderModule->AddIncomingRenderStream(streamId1, 0, 0.55f, 0.0f, 1.0f, 0.45f);
433     assert(renderCallback1 != NULL);
434     printf("Add stream 2\n");
435     const int streamId2 = 2;
436     VideoRenderCallback* renderCallback2 =
437         renderModule->AddIncomingRenderStream(streamId2, 0, 0.0f, 0.55f, 0.45f, 1.0f);
438     assert(renderCallback2 != NULL);
439     printf("Add stream 3\n");
440     const int streamId3 = 3;
441     VideoRenderCallback* renderCallback3 =
442         renderModule->AddIncomingRenderStream(streamId3, 0, 0.55f, 0.55f, 1.0f, 1.0f);
443     assert(renderCallback3 != NULL);
444     error = renderModule->StartRender(streamId0);
445     if (error != 0) {
446       // TODO(phoglund): This test will not work if compiled in release mode.
447       // This rather silly construct here is to avoid compilation errors when
448       // compiling in release. Release => no asserts => unused 'error' variable.
449       assert(false);
450     }
451     error = renderModule->StartRender(streamId1);
452     assert(error == 0);
453     error = renderModule->StartRender(streamId2);
454     assert(error == 0);
455     error = renderModule->StartRender(streamId3);
456     assert(error == 0);
457
458     // Loop through an I420 file and render each frame
459     const int width = 352;
460     const int half_width = (width + 1) / 2;
461     const int height = 288;
462
463     I420VideoFrame videoFrame0;
464     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
465     I420VideoFrame videoFrame1;
466     videoFrame1.CreateEmptyFrame(width, height, width, half_width, half_width);
467     I420VideoFrame videoFrame2;
468     videoFrame2.CreateEmptyFrame(width, height, width, half_width, half_width);
469     I420VideoFrame videoFrame3;
470     videoFrame3.CreateEmptyFrame(width, height, width, half_width, half_width);
471
472     const uint32_t renderDelayMs = 500;
473
474     // Render frames with the specified delay.
475     for (int i=0; i<TEST_FRAME_NUM; i++) {
476       GetTestVideoFrame(&videoFrame0, TEST_STREAM0_START_COLOR);
477
478       videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp() +
479                                      renderDelayMs);
480       renderCallback0->RenderFrame(streamId0, videoFrame0);
481
482       GetTestVideoFrame(&videoFrame1, TEST_STREAM1_START_COLOR);
483       videoFrame1.set_render_time_ms(TickTime::MillisecondTimestamp() +
484                                      renderDelayMs);
485       renderCallback1->RenderFrame(streamId1, videoFrame1);
486
487       GetTestVideoFrame(&videoFrame2,  TEST_STREAM2_START_COLOR);
488       videoFrame2.set_render_time_ms(TickTime::MillisecondTimestamp() +
489                                      renderDelayMs);
490       renderCallback2->RenderFrame(streamId2, videoFrame2);
491
492       GetTestVideoFrame(&videoFrame3, TEST_STREAM3_START_COLOR);
493       videoFrame3.set_render_time_ms(TickTime::MillisecondTimestamp() +
494                                      renderDelayMs);
495       renderCallback3->RenderFrame(streamId3, videoFrame3);
496
497       SleepMs(1000/TEST_FRAME_RATE);
498     }
499
500     // Shut down
501     printf("Closing...\n");
502     error = renderModule->StopRender(streamId0);
503     assert(error == 0);
504     error = renderModule->DeleteIncomingRenderStream(streamId0);
505     assert(error == 0);
506     error = renderModule->StopRender(streamId1);
507     assert(error == 0);
508     error = renderModule->DeleteIncomingRenderStream(streamId1);
509     assert(error == 0);
510     error = renderModule->StopRender(streamId2);
511     assert(error == 0);
512     error = renderModule->DeleteIncomingRenderStream(streamId2);
513     assert(error == 0);
514     error = renderModule->StopRender(streamId3);
515     assert(error == 0);
516     error = renderModule->DeleteIncomingRenderStream(streamId3);
517     assert(error == 0);
518
519     return 0;
520 }
521
522 int TestExternalRender(VideoRender* renderModule) {
523     int error = 0;
524     MyRenderCallback *externalRender = new MyRenderCallback();
525
526     const int streamId0 = 0;
527     VideoRenderCallback* renderCallback0 =
528         renderModule->AddIncomingRenderStream(streamId0, 0, 0.0f, 0.0f,
529                                                    1.0f, 1.0f);
530     assert(renderCallback0 != NULL);
531     error = renderModule->AddExternalRenderCallback(streamId0, externalRender);
532     if (error != 0) {
533       // TODO(phoglund): This test will not work if compiled in release mode.
534       // This rather silly construct here is to avoid compilation errors when
535       // compiling in release. Release => no asserts => unused 'error' variable.
536       assert(false);
537     }
538
539     error = renderModule->StartRender(streamId0);
540     assert(error == 0);
541
542     const int width = 352;
543     const int half_width = (width + 1) / 2;
544     const int height = 288;
545     I420VideoFrame videoFrame0;
546     videoFrame0.CreateEmptyFrame(width, height, width, half_width, half_width);
547
548     const uint32_t renderDelayMs = 500;
549     int frameCount = TEST_FRAME_NUM;
550     for (int i=0; i<frameCount; i++) {
551         videoFrame0.set_render_time_ms(TickTime::MillisecondTimestamp() +
552                                        renderDelayMs);
553         renderCallback0->RenderFrame(streamId0, videoFrame0);
554         SleepMs(33);
555     }
556
557     // Sleep and let all frames be rendered before closing
558     SleepMs(2*renderDelayMs);
559
560     // Shut down
561     printf("Closing...\n");
562     error = renderModule->StopRender(streamId0);
563     assert(error == 0);
564     error = renderModule->DeleteIncomingRenderStream(streamId0);
565     assert(error == 0);
566     assert(frameCount == externalRender->_cnt);
567
568     delete externalRender;
569     externalRender = NULL;
570
571     return 0;
572 }
573
574 void RunVideoRenderTests(void* window, VideoRenderType windowType) {
575     int myId = 12345;
576
577     // Create the render module
578     printf("Create render module\n");
579     VideoRender* renderModule = NULL;
580     renderModule = VideoRender::CreateVideoRender(myId,
581                                                   window,
582                                                   false,
583                                                   windowType);
584     assert(renderModule != NULL);
585
586     // ##### Test single stream rendering ####
587     printf("#### TestSingleStream ####\n");
588     if (TestSingleStream(renderModule) != 0) {
589         printf ("TestSingleStream failed\n");
590     }
591
592     // ##### Test fullscreen rendering ####
593     printf("#### TestFullscreenStream ####\n");
594     if (TestFullscreenStream(renderModule, window, windowType) != 0) {
595         printf ("TestFullscreenStream failed\n");
596     }
597
598     // ##### Test bitmap and text ####
599     printf("#### TestBitmapText ####\n");
600     if (TestBitmapText(renderModule) != 0) {
601         printf ("TestBitmapText failed\n");
602     }
603
604     // ##### Test multiple streams ####
605     printf("#### TestMultipleStreams ####\n");
606     if (TestMultipleStreams(renderModule) != 0) {
607         printf ("TestMultipleStreams failed\n");
608     }
609
610     // ##### Test multiple streams ####
611     printf("#### TestExternalRender ####\n");
612     if (TestExternalRender(renderModule) != 0) {
613         printf ("TestExternalRender failed\n");
614     }
615
616     delete renderModule;
617     renderModule = NULL;
618
619     printf("VideoRender unit tests passed.\n");
620 }
621
622 // Note: The Mac main is implemented in testApi_mac.mm.
623 #if defined(_WIN32)
624 int _tmain(int argc, _TCHAR* argv[])
625 #elif defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
626 int main(int argc, char* argv[])
627 #endif
628 #if !defined(WEBRTC_MAC) && !defined(WEBRTC_ANDROID)
629 {
630     // Create a window for testing.
631     void* window = NULL;
632 #if defined (_WIN32)
633     HWND testHwnd;
634     WebRtcCreateWindow(testHwnd, 0, 352, 288);
635     window = (void*)testHwnd;
636     VideoRenderType windowType = kRenderWindows;
637 #elif defined(WEBRTC_LINUX)
638     Window testWindow;
639     Display* display;
640     WebRtcCreateWindow(&testWindow, &display, 0, 352, 288);
641     VideoRenderType windowType = kRenderX11;
642     window = (void*)testWindow;
643 #endif // WEBRTC_LINUX
644
645     RunVideoRenderTests(window, windowType);
646     return 0;
647 }
648 #endif  // !WEBRTC_MAC