You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
6.3KB

  1. /*
  2. * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
  3. *
  4. * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
  5. *
  6. * Use of this source code is governed by MIT license that can be found in the
  7. * LICENSE file in the root of the source tree. All contributing project authors
  8. * may be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #ifndef YUVDISPLAYER_H_
  11. #define YUVDISPLAYER_H_
  12. #include <stdexcept>
  13. #include "Util/onceToken.h"
  14. #ifdef __cplusplus
  15. extern "C" {
  16. #endif
  17. #include "SDL2/SDL.h"
  18. #include "libavcodec/avcodec.h"
  19. #ifdef __cplusplus
  20. }
  21. #endif
  22. #if defined(_WIN32)
  23. #pragma comment(lib,"SDL2.lib")
  24. #endif //defined(_WIN32)
  25. #define REFRESH_EVENT (SDL_USEREVENT + 1)
  26. class SDLDisplayerHelper
  27. {
  28. public:
  29. static SDLDisplayerHelper &Instance(){
  30. static SDLDisplayerHelper *instance(new SDLDisplayerHelper);
  31. return *instance;
  32. }
  33. static void Destory(){
  34. delete &Instance();
  35. }
  36. template<typename FUN>
  37. void doTask(FUN &&f){
  38. {
  39. std::lock_guard<std::mutex> lck(_mtxTask);
  40. _taskList.emplace_back(f);
  41. }
  42. SDL_Event event;
  43. event.type = REFRESH_EVENT;
  44. SDL_PushEvent(&event);
  45. }
  46. void runLoop(){
  47. bool flag = true;
  48. std::function<bool ()> task;
  49. SDL_Event event;
  50. while(flag){
  51. SDL_WaitEvent(&event);
  52. switch (event.type){
  53. case REFRESH_EVENT: {
  54. {
  55. std::lock_guard<std::mutex> lck(_mtxTask);
  56. if (_taskList.empty()) {
  57. // not reachable
  58. continue;
  59. }
  60. task = _taskList.front();
  61. _taskList.pop_front();
  62. }
  63. flag = task();
  64. break;
  65. }
  66. case SDL_QUIT:{
  67. InfoL << event.type;
  68. return;
  69. }
  70. default:
  71. break;
  72. }
  73. }
  74. }
  75. void shutdown(){
  76. doTask([](){return false;});
  77. }
  78. private:
  79. SDLDisplayerHelper(){
  80. };
  81. ~SDLDisplayerHelper(){
  82. shutdown();
  83. };
  84. private:
  85. std::deque<std::function<bool ()> > _taskList;
  86. std::mutex _mtxTask;
  87. };
  88. class YuvDisplayer {
  89. public:
  90. using Ptr = std::shared_ptr<YuvDisplayer>;
  91. YuvDisplayer(void *hwnd = nullptr,const char *title = "untitled"){
  92. static toolkit::onceToken token([]() {
  93. if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) == -1) {
  94. std::string err = "初始化SDL失败:";
  95. err+= SDL_GetError();
  96. ErrorL << err;
  97. throw std::runtime_error(err);
  98. }
  99. SDL_LogSetAllPriority(SDL_LOG_PRIORITY_CRITICAL);
  100. SDL_LogSetOutputFunction([](void *userdata, int category, SDL_LogPriority priority, const char *message) {
  101. DebugL << category << " " << priority << message;
  102. }, nullptr);
  103. InfoL << "SDL_Init";
  104. }, []() {
  105. SDLDisplayerHelper::Destory();
  106. SDL_Quit();
  107. });
  108. _title = title;
  109. _hwnd = hwnd;
  110. }
  111. virtual ~YuvDisplayer(){
  112. if (_texture) {
  113. SDL_DestroyTexture(_texture);
  114. _texture = nullptr;
  115. }
  116. if (_render) {
  117. SDL_DestroyRenderer(_render);
  118. _render = nullptr;
  119. }
  120. if (_win) {
  121. SDL_DestroyWindow(_win);
  122. _win = nullptr;
  123. }
  124. }
  125. bool displayYUV(AVFrame *pFrame){
  126. if (!_win) {
  127. if (_hwnd) {
  128. _win = SDL_CreateWindowFrom(_hwnd);
  129. }else {
  130. _win = SDL_CreateWindow(_title.data(),
  131. SDL_WINDOWPOS_UNDEFINED,
  132. SDL_WINDOWPOS_UNDEFINED,
  133. pFrame->width,
  134. pFrame->height,
  135. SDL_WINDOW_OPENGL);
  136. }
  137. }
  138. if (_win && ! _render){
  139. #if 0
  140. SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */
  141. SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware
  142. acceleration */
  143. SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized
  144. with the refresh rate */
  145. SDL_RENDERER_TARGETTEXTURE = 0x00000008 /**< The renderer supports
  146. rendering to texture */
  147. #endif
  148. _render = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED);
  149. }
  150. if (_render && !_texture) {
  151. if (pFrame->format == AV_PIX_FMT_NV12) {
  152. _texture = SDL_CreateTexture(
  153. _render, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STREAMING, pFrame->width, pFrame->height);
  154. } else {
  155. _texture = SDL_CreateTexture(
  156. _render, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pFrame->width, pFrame->height);
  157. }
  158. }
  159. if (_texture) {
  160. #if SDL_VERSION_ATLEAST(2,0,16)
  161. //需要更新sdl到最新(>=2.0.16)
  162. if (pFrame->format == AV_PIX_FMT_NV12) {
  163. SDL_UpdateNVTexture(
  164. _texture, nullptr, pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1]);
  165. } else
  166. #endif
  167. {
  168. SDL_UpdateYUVTexture(
  169. _texture, nullptr, pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1],
  170. pFrame->data[2], pFrame->linesize[2]);
  171. }
  172. //SDL_UpdateTexture(_texture, nullptr, pFrame->data[0], pFrame->linesize[0]);
  173. SDL_RenderClear(_render);
  174. SDL_RenderCopy(_render, _texture, nullptr, nullptr);
  175. SDL_RenderPresent(_render);
  176. return true;
  177. }
  178. return false;
  179. }
  180. private:
  181. std::string _title;
  182. SDL_Window *_win = nullptr;
  183. SDL_Renderer *_render = nullptr;
  184. SDL_Texture *_texture = nullptr;
  185. void *_hwnd = nullptr;
  186. };
  187. #endif /* YUVDISPLAYER_H_ */