YuvDisplayer.h 5.84 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
xzl committed
3
 *
xiongziliang committed
4
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
xiongziliang committed
5
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
xzl committed
9
 */
xiongziliang committed
10

xzl committed
11 12 13 14 15 16 17
#ifndef YUVDISPLAYER_H_
#define YUVDISPLAYER_H_
#include <stdexcept>
#include "Util/onceToken.h"
#ifdef __cplusplus
extern "C" {
#endif
xiongziliang committed
18 19
#include "SDL2/SDL.h"
#include "libavcodec/avcodec.h"
xzl committed
20 21 22 23
#ifdef __cplusplus
}
#endif

xiongziliang committed
24 25 26 27
#if defined(_WIN32)
#pragma comment(lib,"SDL2.lib")
#endif //defined(_WIN32)

xiongziliang committed
28 29
using namespace toolkit;
using namespace mediakit;
xiongziliang committed
30 31 32

#define REFRESH_EVENT   (SDL_USEREVENT + 1)

33

xiongziliang committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
class SDLDisplayerHelper
{
public:
    static SDLDisplayerHelper &Instance(){
        static SDLDisplayerHelper *instance(new SDLDisplayerHelper);
        return *instance;
    }
    static void Destory(){
        delete &Instance();
    }
    template<typename FUN>
    void doTask(FUN &&f){
        {
            lock_guard<mutex> lck(_mtxTask);
            _taskList.emplace_back(f);
        }
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
    }

55 56 57 58 59 60 61
    void runLoop(){
        bool flag = true;
        std::function<bool ()> task;
        SDL_Event event;
        while(flag){
            SDL_WaitEvent(&event);
            switch (event.type){
xiongziliang committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
                case REFRESH_EVENT:{
                    {
                        lock_guard<mutex> lck(_mtxTask);
                        if(_taskList.empty()){
                            //not reachable
                            continue;
                        }
                        task = _taskList.front();
                        _taskList.pop_front();
                    }
                    flag = task();
                    break;
                case SDL_QUIT:
                    InfoL << event.type;
                    return;
                }
                default:
                    break;
            }
81 82
        }
    }
xiongziliang committed
83

84 85 86
    void shutdown(){
        doTask([](){return false;});
    }
xiongziliang committed
87 88 89 90
private:
    SDLDisplayerHelper(){
    };
    ~SDLDisplayerHelper(){
91
        shutdown();
xiongziliang committed
92
    };
xiongziliang committed
93
private:
xiongziliang committed
94 95 96 97
    std::deque<std::function<bool ()> > _taskList;
    std::mutex _mtxTask;

};
xzl committed
98

99

xzl committed
100 101
class YuvDisplayer {
public:
102
    YuvDisplayer(void *hwnd = nullptr,const char *title = "untitled"){
xiongziliang committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

        static onceToken token([]() {
            if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) == -1) {
                string err = "初始化SDL失败:";
                err+= SDL_GetError();
                ErrorL << err;
                throw std::runtime_error(err);
            }
            SDL_LogSetAllPriority(SDL_LOG_PRIORITY_CRITICAL);
            SDL_LogSetOutputFunction([](void *userdata, int category, SDL_LogPriority priority, const char *message){
                DebugL << category << " " <<  priority << message;
            },nullptr);
            InfoL << "SDL_Init";
        }, []() {
            SDLDisplayerHelper::Destory();
            SDL_Quit();
        });

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
        _title = title;
        _hwnd = hwnd;
    }
    virtual ~YuvDisplayer(){
        if (_texture) {
            SDL_DestroyTexture(_texture);
            _texture = nullptr;
        }
        if (_render) {
            SDL_DestroyRenderer(_render);
            _render = nullptr;
        }
        if (_win) {
            SDL_DestroyWindow(_win);
            _win = nullptr;
        }
    }
    bool displayYUV(AVFrame *pFrame){
        if (!_win) {
            if (_hwnd) {
                _win = SDL_CreateWindowFrom(_hwnd);
            }else {
                _win = SDL_CreateWindow(_title.data(),
                                        SDL_WINDOWPOS_UNDEFINED,
                                        SDL_WINDOWPOS_UNDEFINED,
                                        pFrame->width,
                                        pFrame->height,
                                        SDL_WINDOW_OPENGL);
            }
        }
        if (_win && ! _render){
xiongziliang committed
152
#if 0
153
            SDL_RENDERER_SOFTWARE = 0x00000001,         /**< The renderer is a software fallback */
xiongziliang committed
154 155 156 157 158 159 160
                    SDL_RENDERER_ACCELERATED = 0x00000002,      /**< The renderer uses hardware
                                                                     acceleration */
                    SDL_RENDERER_PRESENTVSYNC = 0x00000004,     /**< Present is synchronized
                                                                     with the refresh rate */
                    SDL_RENDERER_TARGETTEXTURE = 0x00000008     /**< The renderer supports
                                                                     rendering to texture */
#endif
xiongziliang committed
161

162 163 164 165 166 167 168 169 170 171 172 173 174
            _render = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED);
        }
        if (_render && !_texture) {
            _texture = SDL_CreateTexture(_render, SDL_PIXELFORMAT_IYUV,
                                         SDL_TEXTUREACCESS_STREAMING,
                                         pFrame->width,
                                         pFrame->height);
        }
        if (_texture) {
            SDL_UpdateYUVTexture(_texture, nullptr,
                                 pFrame->data[0], pFrame->linesize[0],
                                 pFrame->data[1], pFrame->linesize[1],
                                 pFrame->data[2], pFrame->linesize[2]);
xiongziliang committed
175

176 177 178 179 180 181 182 183
            //SDL_UpdateTexture(_texture, nullptr, pFrame->data[0], pFrame->linesize[0]);
            SDL_RenderClear(_render);
            SDL_RenderCopy(_render, _texture, nullptr, nullptr);
            SDL_RenderPresent(_render);
            return true;
        }
        return false;
    }
xzl committed
184
private:
185 186 187 188 189
    string _title;
    SDL_Window *_win = nullptr;
    SDL_Renderer *_render = nullptr;
    SDL_Texture *_texture = nullptr;
    void *_hwnd = nullptr;
xzl committed
190 191
};

xiongziliang committed
192
#endif /* YUVDISPLAYER_H_ */