Linux 환경에서 QML + SDL 로 SDL window 를 구현하는 것은 상당히 까다로운 작업이 아닐 수 없다. 그 이유는 Window 에서 C++ 을 통한 구현 처럼 SDL_CreateWindowFrom(HWND hwnd) 을 이용한 구현이 쉽지 않기 때문이다.

보통의 경우 SDL_CreateWindow 를 이용하여 구현을 하게 되는데, 이는 결과적으로 QML Window 에서 SDL Wondow 가 동작하는 것이 아니라 별도의 2개의 window 에서 동작하게 되는 결과를 낳게 된다. google search 를 통한 검색을 통해서도 이를 해결하기 위한 방법을 찾을 수가 없다. 그러나 우리는 결국 구현을 하였고 이러한 결과를 얻고자 하는 많은 개발자를 위해 우리의 Know-how 를 공개하기로 했다.

현재 우리가 개발하고 있는 AVB_player 에 대해 전체 공개는 어렵기에 QML+SDL 구현의 기본 개념을 아래에서 설명하고자 한다. 참고로 Ocube AVB player 는 Linux 환경에서 pcap + ffmpeg + SDL2.0 으로 구성되어 있으며, 먼저 아래에 Ocube AVB Analyzer 영상을 간단히 시청해 보자

그럼 지금 부터 QML 에서 SDL window 를 올리는 방법에 대해서 이야기 해보자. 기본적으로 SDL2 라이브러리가 설치되어야 하며, 정상적으로 Qt project 에서 읽어올 수 있어야 한다. 이 방법에 대해서는 기술하지 않으나, 궁금한 부분에 대해서는 Q&A 를 통하여 질문시 답변을 드릴 수 있을 것이다.

1. QML 구성

먼저 QML 구성을 할때 QtObjcet 에 전체 Application Window (objectName: MainWindow) 와 SDL을 통한 영상이 Play 될 Application Window (objectName: SDLWindow) 를 구성한다.

[main.qml] [code language=”cpp”] import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2

QtObject {
property var win1 : ApplicationWindow {
id: _mainWin
width: 1280
height: 720
objectName: "MainWindow"
…..
}

property var win2 : ApplicationWindow {
objectName: "SDLWindow"
x: 0
y: 0
width: 200
height: 200
color: "transparent"
}
}[/code]

2. main 함수 구성

main 함수에서는 기 작성된 main.qml 을 QQmlApplicationEngine 으로 load 한 후 engine 의 root 에서 main.qml 에서 생성한 objectName 으로 chind를 찾아서 QQucickWindow 에 할당을 한다. 이렇게 생성된 win(MainWindow), win2(SDLWindow) 에 대해서 win2->setParent(win) 를 통해 Parent-Child 설정을 하게 되면 window 의 관계가 완성이 된다. 이제 남은 것은 SDL 을 win2 에 띄우는 일만 남았다.

[main.cpp] [code language=”cpp”] #include <QApplication>
#include <QQuickWindow>
#include <QQmlApplicationEngine>
#include <SDL2/SDL.h>
#include <QDebug>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

QObject *root = engine.rootObjects().at(0);
QQuickWindow *win = root->findChild<QQuickWindow*>(QString("MainWindow"));

if(win != NULL)
win->setProperty("visible", true);

QQuickWindow *win2 = root->findChild<QQuickWindow*>(QString("SDLWindow"));
if(win2 != NULL) {
win2->setParent(win);
win2->setProperty("visible", true);

/*SDL Start here*/
…..
/*SDL End*/
}
return app.exec();
}[/code]

3. SDL

위 2번 항목의 /*SDL Start here*/ 와 /*SDL End*/ 사이에 SDL 을 구현해 보자. 실제 프로젝트에서는 함수 또는 Class 를 통해 구현을 하겠지만 여기에서는 간단히 사각형을 그리는 정도로 구현을 하고자 한다.
QML 로 구현한 Application 에서 가장 중요한 것은 시작에서 이야기 했던 것 처럼 SDL_CreateWindowFrom 을 통한 단일 Window 를 구현하는 것이다. 2번항목에서 생성한 win2(SDLWindow) 의 winId() 를 SDL_CreateWindowFrom 으로 넘겨주게 되면 해결이 된다. 이 부분이 가장 중요한 부분이고 이 글에서 이야기 하고자 하는 내용의 핵심이다. 결국 아래 code 는 win2 영역에 SDL_Rect 를 그리게 된다.

[code language=”cpp”] /*SDL Start here*/
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindowFrom((void*)win2->winId());

SDL_Renderer* renderer = NULL;
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_SOFTWARE);

SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 );
SDL_RenderClear( renderer );

// Creat a rect at pos ( 50, 50 ) that’s 50 pixels wide and 50 pixels high.
SDL_Rect r;
r.x = 50;
r.y = 50;
r.w = 50;
r.h = 50;

// Set render color to blue ( rect will be rendered in this color )
SDL_SetRenderDrawColor( renderer, 0, 0, 255, 255 );

// Render rect
SDL_RenderFillRect( renderer, &r );

// Render the rect to the screen
SDL_RenderPresent(renderer);
/*SDL End*/[/code]

우리는 위 code example 을 통해 QML 에서 SDL 을 사용하는 방법에 대한 개념을 살펴 보았다. 좀 더 자세한 내용에 대해서 이야기하고 우리와 커뮤니케이션을 하고 싶다면 Q&A or Contact US 를 통해 문의를 하기 바란다.