libvideorender.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #include"libvideorender.h"
  2. #include "videoutil.h"
  3. #include <string.h>
  4. //Refresh Event
  5. #ifndef REFRESH_EVENT
  6. #define REFRESH_EVENT (SDL_USEREVENT + 1)
  7. #endif
  8. #ifndef RVC_DEFAULT_DELAY_TIME
  9. #define RVC_DEFAULT_DELAY_TIME 1
  10. #endif
  11. VideoRenderImpl::VideoRenderImpl(videorender_callback_t* pCallback)
  12. {
  13. m_sdl_window = NULL;
  14. m_rending_texture = NULL;
  15. m_renderer = NULL;
  16. memcpy(&m_callback, pCallback, sizeof(videorender_callback_t));
  17. m_refresh_flag = false;
  18. m_bmoveable = false;
  19. m_refresh_thread = NULL;
  20. m_x = SDL_WINDOWPOS_UNDEFINED;
  21. m_y = SDL_WINDOWPOS_UNDEFINED;
  22. m_width = 0;
  23. m_height = 0;
  24. m_videoformat = VIDEO_FORMAT_RGB24;
  25. m_flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_HIDDEN | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU;
  26. }
  27. VideoRenderImpl::~VideoRenderImpl()
  28. {
  29. if (NULL != m_rending_texture) {
  30. SDL_DestroyTexture(m_rending_texture);
  31. m_rending_texture = NULL;
  32. //RenderLog(RENDER_LOG_DEBUG, "DestroyTexture.");
  33. }
  34. if (NULL != m_renderer) {
  35. SDL_DestroyRenderer(m_renderer);
  36. m_renderer = NULL;
  37. //RenderLog(RENDER_LOG_DEBUG, "DestroyRenderer.");
  38. }
  39. if (NULL != m_sdl_window) {
  40. SDL_DestroyWindow(m_sdl_window);
  41. m_sdl_window = NULL;
  42. //RenderLog(RENDER_LOG_DEBUG, "DestroyWindow.");
  43. }
  44. }
  45. int VideoRenderImpl::SetWindowProperty(videorender_param_t* tparam)
  46. {
  47. int iRet = -1;
  48. if (NULL == tparam){
  49. return iRet;
  50. }
  51. m_x = tparam->icx;
  52. m_y = tparam->icy;
  53. m_width = tparam->uwidth;
  54. m_height = tparam->uheight;
  55. m_videowidth = m_width;
  56. m_videoheight = m_height;
  57. if (tparam->uvideowidth > 0){
  58. m_videowidth = tparam->uvideowidth;
  59. }
  60. if (tparam->uvideoheight > 0){
  61. m_videoheight = tparam->uvideoheight;
  62. }
  63. m_videoformat = tparam->ivideoformat;
  64. iRet = 0;
  65. return iRet;
  66. }
  67. SDL_PixelFormatEnum VideoRenderImpl::GetPixelFormat()
  68. {
  69. SDL_PixelFormatEnum eType = SDL_PIXELFORMAT_BGR24;
  70. if (VIDEO_FORMAT_I420 == m_videoformat){
  71. eType = SDL_PIXELFORMAT_IYUV;
  72. }
  73. return eType;
  74. }
  75. int VideoRenderImpl::VideoRenderSetParam(videorender_param_t* tparam)
  76. {
  77. if (SetWindowProperty(tparam)){
  78. RenderLog(RENDER_LOG_ERROR, "SetWindowProperty failed for param error.");
  79. return -1;
  80. }
  81. if (NULL == m_sdl_window){
  82. SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
  83. m_sdl_window = SDL_CreateWindow(
  84. "", // window title
  85. m_x, // initial x position
  86. m_y, // initial y position
  87. m_width, // width, in pixels
  88. m_height, // height, in pixels
  89. m_flags
  90. );
  91. if (NULL == m_sdl_window){
  92. RenderLog(RENDER_LOG_ERROR, "RENDER: (SDL2) Couldn't open window: %s", SDL_GetError());
  93. VideoRenderDestroy();
  94. return -2;
  95. }
  96. int idisplay_index = SDL_GetWindowDisplayIndex(m_sdl_window);
  97. if (-1 == idisplay_index) {
  98. RenderLog(RENDER_LOG_ERROR, "RENDER: get window dispaly index failed!");
  99. return -3;
  100. }
  101. SDL_DisplayMode display_mode;
  102. int err = SDL_GetDesktopDisplayMode(idisplay_index, &display_mode);
  103. if (0 == err){
  104. RenderLog(RENDER_LOG_DEBUG, "RENDER: video display %i -> %dx%dpx @ %dhz",
  105. idisplay_index,
  106. display_mode.w,
  107. display_mode.h,
  108. display_mode.refresh_rate);
  109. }
  110. else {
  111. RenderLog(RENDER_LOG_ERROR, "RENDER: Couldn't determine display mode for video display %i", idisplay_index);
  112. }
  113. if (m_width > display_mode.w) {
  114. m_width = display_mode.w;
  115. }
  116. if (m_height > display_mode.h) {
  117. m_height = display_mode.h;
  118. }
  119. SDL_SetWindowSize(m_sdl_window, m_width, m_height);
  120. }
  121. static bool blog = true;
  122. /* Print the list of the available renderers*/
  123. if (blog) {
  124. RenderLog(RENDER_LOG_DEBUG, "RENDER: Available SDL2 rendering drivers:");
  125. }
  126. SDL_RendererInfo rend_info;
  127. for (int i = 0; i < SDL_GetNumRenderDrivers(); i++){
  128. if (SDL_GetRenderDriverInfo(i, &rend_info) < 0){
  129. RenderLog(RENDER_LOG_ERROR, "Couldn't get SDL2 render driver information: %s", SDL_GetError());
  130. }
  131. else {
  132. if (blog) {
  133. RenderLog(RENDER_LOG_DEBUG, " %2d: %s", i, rend_info.name);
  134. }
  135. //RenderLog(RENDER_LOG_DEBUG," SDL_RENDERER_TARGETTEXTURE [%c]", (rend_info.flags & SDL_RENDERER_TARGETTEXTURE) ? 'X' : ' ');
  136. //RenderLog(RENDER_LOG_DEBUG," SDL_RENDERER_SOFTWARE [%c]", (rend_info.flags & SDL_RENDERER_SOFTWARE) ? 'X' : ' ');
  137. //RenderLog(RENDER_LOG_DEBUG," SDL_RENDERER_ACCELERATED [%c]", (rend_info.flags & SDL_RENDERER_ACCELERATED) ? 'X' : ' ');
  138. //RenderLog(RENDER_LOG_DEBUG," SDL_RENDERER_PRESENTVSYNC [%c]", (rend_info.flags & SDL_RENDERER_PRESENTVSYNC) ? 'X' : ' ');
  139. }
  140. }
  141. m_renderer = SDL_CreateRenderer(m_sdl_window, -1,
  142. SDL_RENDERER_TARGETTEXTURE |
  143. SDL_RENDERER_PRESENTVSYNC |
  144. SDL_RENDERER_ACCELERATED);
  145. if (m_renderer == NULL)
  146. {
  147. RenderLog(RENDER_LOG_ERROR, "RENDER: (SDL2) Couldn't get a accelerated renderer: %s", SDL_GetError());
  148. RenderLog(RENDER_LOG_INFO, "RENDER: (SDL2) trying with a software renderer");
  149. m_renderer = SDL_CreateRenderer(m_sdl_window, -1,
  150. SDL_RENDERER_TARGETTEXTURE |
  151. SDL_RENDERER_SOFTWARE);
  152. if (m_renderer == NULL){
  153. RenderLog(RENDER_LOG_ERROR, "RENDER: (SDL2) Couldn't get a software renderer: %s", SDL_GetError());
  154. RenderLog(RENDER_LOG_ERROR, "RENDER: (SDL2) giving up...");
  155. VideoRenderDestroy();
  156. return -3;
  157. }
  158. }
  159. /* Print the name of the current rendering driver */
  160. SDL_RendererInfo render_info;
  161. if (SDL_GetRendererInfo(m_renderer, &render_info) < 0){
  162. RenderLog(RENDER_LOG_ERROR, "Couldn't get SDL2 rendering driver information: %s", SDL_GetError());
  163. }
  164. if (blog) {
  165. RenderLog(RENDER_LOG_DEBUG, "RENDER: rendering driver in use: %s", render_info.name);
  166. }
  167. //RenderLog(RENDER_LOG_DEBUG, " SDL_RENDERER_TARGETTEXTURE [%c]", (render_info.flags & SDL_RENDERER_TARGETTEXTURE) ? 'X' : ' ');
  168. //RenderLog(RENDER_LOG_DEBUG, " SDL_RENDERER_SOFTWARE [%c]", (render_info.flags & SDL_RENDERER_SOFTWARE) ? 'X' : ' ');
  169. //RenderLog(RENDER_LOG_DEBUG, " SDL_RENDERER_ACCELERATED [%c]", (render_info.flags & SDL_RENDERER_ACCELERATED) ? 'X' : ' ');
  170. //RenderLog(RENDER_LOG_DEBUG, " SDL_RENDERER_PRESENTVSYNC [%c]", (render_info.flags & SDL_RENDERER_PRESENTVSYNC) ? 'X' : ' ');
  171. blog = false;
  172. SDL_RenderSetLogicalSize(m_renderer, m_videowidth, m_videoheight);
  173. SDL_SetRenderDrawBlendMode(m_renderer, SDL_BLENDMODE_NONE);
  174. m_rending_texture = SDL_CreateTexture(m_renderer,
  175. GetPixelFormat(),
  176. SDL_TEXTUREACCESS_STREAMING,
  177. m_videowidth,
  178. m_videoheight);
  179. if (m_rending_texture == NULL){
  180. RenderLog(RENDER_LOG_ERROR, "RENDER: (SDL2) Couldn't get a texture for rendering: %s", SDL_GetError());
  181. VideoRenderDestroy();
  182. return -4;
  183. }
  184. return 0;
  185. }
  186. static int refresh_video(void *opaque)
  187. {
  188. VideoRenderImpl* pImpl = (VideoRenderImpl*)opaque;
  189. while (pImpl->GetReFreshFlag()) {
  190. SDL_Event event;
  191. event.type = REFRESH_EVENT;
  192. SDL_PushEvent(&event);
  193. SDL_Delay(RVC_DEFAULT_DELAY_TIME);
  194. }
  195. return 0;
  196. }
  197. static SDL_HitTestResult SDLCALL SDL_HitTestCallback(SDL_Window *win, const SDL_Point *area, void *data)
  198. {
  199. VideoRenderImpl* pImpl = (VideoRenderImpl*)data;
  200. int iwidth = 0, iheight = 0;
  201. SDL_GetWindowSize(win, &iwidth, &iheight);
  202. pImpl->RenderLog(RENDER_LOG_DEBUG, "window width is %d, height is %d.", iwidth, iheight);
  203. pImpl->RenderLog(RENDER_LOG_DEBUG, "area->x = %d, area->y = %d.", area->x, area->y);
  204. return SDL_HITTEST_DRAGGABLE;
  205. }
  206. bool VideoRenderImpl::GetReFreshFlag()
  207. {
  208. return m_refresh_flag;
  209. }
  210. int VideoRenderImpl::StartVideoRender()
  211. {
  212. m_refresh_flag = true;
  213. m_refresh_thread = SDL_CreateThread(refresh_video,"refresh video thread", this);
  214. if (NULL == m_refresh_thread) {
  215. RenderLog(RENDER_LOG_ERROR, "SDL_Create refresh video thread failed: %s.", SDL_GetError());
  216. return -1;
  217. }
  218. if (m_bmoveable){
  219. if (0 != SDL_SetWindowHitTest(m_sdl_window, SDL_HitTestCallback, this)) {
  220. RenderLog(RENDER_LOG_ERROR, "SDL_SetWindowHitTest failed: %s.", SDL_GetError());
  221. return -1;
  222. }
  223. }
  224. return 0;
  225. }
  226. int VideoRenderImpl::ShowVideoWindow()
  227. {
  228. int iret = -1;
  229. if (NULL != m_sdl_window){
  230. Uint32 uflags = SDL_GetWindowFlags(m_sdl_window);
  231. if (uflags & SDL_WINDOW_HIDDEN) {
  232. SDL_ShowWindow(m_sdl_window);
  233. }
  234. iret = 0;
  235. }
  236. return iret;
  237. }
  238. int VideoRenderImpl::HideVideoWindow()
  239. {
  240. int iret = -1;
  241. if (NULL != m_sdl_window) {
  242. Uint32 uflags = SDL_GetWindowFlags(m_sdl_window);
  243. if (uflags & SDL_WINDOW_SHOWN) {
  244. SDL_HideWindow(m_sdl_window);
  245. }
  246. iret = 0;
  247. }
  248. return iret;
  249. }
  250. int VideoRenderImpl::StopVideoRender()
  251. {
  252. HideVideoWindow();
  253. m_refresh_flag = false;
  254. if (NULL != m_refresh_thread){
  255. SDL_WaitThread(m_refresh_thread, NULL);
  256. m_refresh_thread = NULL;
  257. }
  258. return 0;
  259. }
  260. void VideoRenderImpl::VideoRenderDestroy()
  261. {
  262. delete this;
  263. }
  264. int VideoRenderImpl::RenderVideoFrame(video_frame* pframe, RVC_RendererFlip eFlipType)
  265. {
  266. int iret = -1;
  267. if (NULL == m_sdl_window || NULL == pframe || NULL == m_renderer || NULL == m_rending_texture){
  268. return iret;
  269. }
  270. SDL_Event event;
  271. SDL_WaitEvent(&event);
  272. if(REFRESH_EVENT == event.type){
  273. SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255); /*black*/
  274. SDL_RenderClear(m_renderer);
  275. /* since data is continuous we can use SDL_UpdateTexture
  276. * instead of SDL_UpdateYUVTexture.
  277. * no need to use SDL_Lock/UnlockTexture (it doesn't seem faster)
  278. */
  279. //SDL_QueryTexture()
  280. if (VIDEO_FORMAT_RGB24 == pframe->format || VIDEO_FORMAT_I420 == pframe->format){
  281. if (VIDEO_FORMAT_RGB24 == pframe->format){
  282. SDL_UpdateTexture(m_rending_texture, NULL, pframe->data[0], pframe->width*3);
  283. }
  284. else{
  285. SDL_UpdateTexture(m_rending_texture, NULL, pframe->data[0], pframe->width);
  286. }
  287. if (RVC_FLIP_NONE == eFlipType){
  288. SDL_RenderCopy(m_renderer, m_rending_texture, NULL, NULL);
  289. }
  290. else{
  291. SDL_Point point = {m_videowidth/2, m_videoheight/2};
  292. SDL_RenderCopyEx(m_renderer, m_rending_texture, NULL, NULL, 0, &point, (SDL_RendererFlip)eFlipType);
  293. }
  294. }
  295. else{
  296. RenderLog(RENDER_LOG_ERROR, "%s:%d not support format, return", __FUNCTION__, __LINE__);
  297. return iret;
  298. }
  299. SDL_RenderPresent(m_renderer);
  300. }
  301. iret = 0;
  302. return iret;
  303. }
  304. void VideoRenderImpl::RenderLog(render_loglevel elevel, const char* fmt, ...)
  305. {
  306. if (m_callback.debug) {
  307. va_list arg;
  308. va_start(arg, fmt);
  309. if (*m_callback.debug){
  310. (*m_callback.debug)(elevel, m_callback.user_data, fmt, arg);
  311. }
  312. va_end(arg);
  313. }
  314. }