2018-02-08 18:14:13 +08:00
|
|
|
#ifndef SCREEN_H
|
|
|
|
#define SCREEN_H
|
|
|
|
|
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
#include <libavformat/avformat.h>
|
|
|
|
|
|
|
|
#include "common.h"
|
2019-03-02 22:16:55 +08:00
|
|
|
|
|
|
|
struct video_buffer;
|
2018-02-08 18:14:13 +08:00
|
|
|
|
|
|
|
struct screen {
|
|
|
|
SDL_Window *window;
|
|
|
|
SDL_Renderer *renderer;
|
|
|
|
SDL_Texture *texture;
|
|
|
|
struct size frame_size;
|
|
|
|
//used only in fullscreen mode to know the windowed window size
|
|
|
|
struct size windowed_window_size;
|
Improve startup time
On startup, the client has to:
1. listen on a port
2. push and start the server to the device
3. wait for the server to connect (accept)
4. read device name and size
5. initialize SDL
6. initialize the window and renderer
7. show the window
From the execution of the app_process command to start the server on the
device, to the execution of the java main method, it takes ~800ms. As a
consequence, step 3 also takes ~800ms on the client.
Once complete, the client initializes SDL, which takes ~500ms.
These two expensive actions are executed sequentially:
HOST DEVICE
listen on port | |
push/start the server |----------------->|| app_process loads the jar
accept the connection . ^ ||
. | ||
. | WASTE ||
. | OF ||
. | TIME ||
. | ||
. | ||
. v X execution of our java main
connection accepted |<-----------------| connect to the host
init SDL || |
|| ,----------------| send frames
|| |,---------------|
|| ||,--------------|
|| |||,-------------|
|| ||||,------------|
init window/renderer | |||||,-----------|
display frames |<++++++-----------|
(many frames skipped)
The rationale for step 3 occuring before step 5 is that initializing
SDL replaces the SIGTERM handler to receive the event in the event loop,
so pressing Ctrl+C during step 5 would not work (since it blocks the
event loop).
But this is not so important; let's parallelize the SDL initialization
with the app_process execution (we'll just add a timeout to the
connection):
HOST DEVICE
listen on port | |
push/start the server |----------------->||app_process loads the jar
init SDL || ||
|| ||
|| ||
|| ||
|| ||
|| ||
accept the connection . ||
. X execution of our java main
connection accepted |<-----------------| connect to the host
init window/renderer | |
display frames |<-----------------| send frames
|<-----------------|
In addition, show the window only once the first frame is available to
avoid flickering (opening a black window for 100~200ms).
Note: the window and renderer are initialized after the connection is
accepted because they use the device information received from the
device.
2018-02-09 20:50:54 +08:00
|
|
|
SDL_bool has_frame;
|
2018-02-08 18:14:13 +08:00
|
|
|
SDL_bool fullscreen;
|
2019-02-02 05:53:24 +08:00
|
|
|
SDL_bool no_window;
|
2018-02-08 18:14:13 +08:00
|
|
|
};
|
|
|
|
|
Improve startup time
On startup, the client has to:
1. listen on a port
2. push and start the server to the device
3. wait for the server to connect (accept)
4. read device name and size
5. initialize SDL
6. initialize the window and renderer
7. show the window
From the execution of the app_process command to start the server on the
device, to the execution of the java main method, it takes ~800ms. As a
consequence, step 3 also takes ~800ms on the client.
Once complete, the client initializes SDL, which takes ~500ms.
These two expensive actions are executed sequentially:
HOST DEVICE
listen on port | |
push/start the server |----------------->|| app_process loads the jar
accept the connection . ^ ||
. | ||
. | WASTE ||
. | OF ||
. | TIME ||
. | ||
. | ||
. v X execution of our java main
connection accepted |<-----------------| connect to the host
init SDL || |
|| ,----------------| send frames
|| |,---------------|
|| ||,--------------|
|| |||,-------------|
|| ||||,------------|
init window/renderer | |||||,-----------|
display frames |<++++++-----------|
(many frames skipped)
The rationale for step 3 occuring before step 5 is that initializing
SDL replaces the SIGTERM handler to receive the event in the event loop,
so pressing Ctrl+C during step 5 would not work (since it blocks the
event loop).
But this is not so important; let's parallelize the SDL initialization
with the app_process execution (we'll just add a timeout to the
connection):
HOST DEVICE
listen on port | |
push/start the server |----------------->||app_process loads the jar
init SDL || ||
|| ||
|| ||
|| ||
|| ||
|| ||
accept the connection . ||
. X execution of our java main
connection accepted |<-----------------| connect to the host
init window/renderer | |
display frames |<-----------------| send frames
|<-----------------|
In addition, show the window only once the first frame is available to
avoid flickering (opening a black window for 100~200ms).
Note: the window and renderer are initialized after the connection is
accepted because they use the device information received from the
device.
2018-02-09 20:50:54 +08:00
|
|
|
#define SCREEN_INITIALIZER { \
|
|
|
|
.window = NULL, \
|
|
|
|
.renderer = NULL, \
|
|
|
|
.texture = NULL, \
|
|
|
|
.frame_size = { \
|
|
|
|
.width = 0, \
|
|
|
|
.height = 0, \
|
|
|
|
}, \
|
|
|
|
.windowed_window_size = { \
|
|
|
|
.width = 0, \
|
|
|
|
.height = 0, \
|
|
|
|
}, \
|
|
|
|
.has_frame = SDL_FALSE, \
|
|
|
|
.fullscreen = SDL_FALSE, \
|
2019-02-02 05:53:24 +08:00
|
|
|
.no_window = SDL_FALSE, \
|
2018-02-08 18:14:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// init SDL and set appropriate hints
|
|
|
|
SDL_bool sdl_init_and_configure(void);
|
|
|
|
|
|
|
|
// initialize default values
|
|
|
|
void screen_init(struct screen *screen);
|
|
|
|
|
Improve startup time
On startup, the client has to:
1. listen on a port
2. push and start the server to the device
3. wait for the server to connect (accept)
4. read device name and size
5. initialize SDL
6. initialize the window and renderer
7. show the window
From the execution of the app_process command to start the server on the
device, to the execution of the java main method, it takes ~800ms. As a
consequence, step 3 also takes ~800ms on the client.
Once complete, the client initializes SDL, which takes ~500ms.
These two expensive actions are executed sequentially:
HOST DEVICE
listen on port | |
push/start the server |----------------->|| app_process loads the jar
accept the connection . ^ ||
. | ||
. | WASTE ||
. | OF ||
. | TIME ||
. | ||
. | ||
. v X execution of our java main
connection accepted |<-----------------| connect to the host
init SDL || |
|| ,----------------| send frames
|| |,---------------|
|| ||,--------------|
|| |||,-------------|
|| ||||,------------|
init window/renderer | |||||,-----------|
display frames |<++++++-----------|
(many frames skipped)
The rationale for step 3 occuring before step 5 is that initializing
SDL replaces the SIGTERM handler to receive the event in the event loop,
so pressing Ctrl+C during step 5 would not work (since it blocks the
event loop).
But this is not so important; let's parallelize the SDL initialization
with the app_process execution (we'll just add a timeout to the
connection):
HOST DEVICE
listen on port | |
push/start the server |----------------->||app_process loads the jar
init SDL || ||
|| ||
|| ||
|| ||
|| ||
|| ||
accept the connection . ||
. X execution of our java main
connection accepted |<-----------------| connect to the host
init window/renderer | |
display frames |<-----------------| send frames
|<-----------------|
In addition, show the window only once the first frame is available to
avoid flickering (opening a black window for 100~200ms).
Note: the window and renderer are initialized after the connection is
accepted because they use the device information received from the
device.
2018-02-09 20:50:54 +08:00
|
|
|
// initialize screen, create window, renderer and texture (window is hidden)
|
2018-02-08 18:14:13 +08:00
|
|
|
SDL_bool screen_init_rendering(struct screen *screen,
|
|
|
|
const char *device_name,
|
2019-01-27 19:04:22 +08:00
|
|
|
struct size frame_size,
|
|
|
|
SDL_bool always_on_top);
|
2018-02-08 18:14:13 +08:00
|
|
|
|
Improve startup time
On startup, the client has to:
1. listen on a port
2. push and start the server to the device
3. wait for the server to connect (accept)
4. read device name and size
5. initialize SDL
6. initialize the window and renderer
7. show the window
From the execution of the app_process command to start the server on the
device, to the execution of the java main method, it takes ~800ms. As a
consequence, step 3 also takes ~800ms on the client.
Once complete, the client initializes SDL, which takes ~500ms.
These two expensive actions are executed sequentially:
HOST DEVICE
listen on port | |
push/start the server |----------------->|| app_process loads the jar
accept the connection . ^ ||
. | ||
. | WASTE ||
. | OF ||
. | TIME ||
. | ||
. | ||
. v X execution of our java main
connection accepted |<-----------------| connect to the host
init SDL || |
|| ,----------------| send frames
|| |,---------------|
|| ||,--------------|
|| |||,-------------|
|| ||||,------------|
init window/renderer | |||||,-----------|
display frames |<++++++-----------|
(many frames skipped)
The rationale for step 3 occuring before step 5 is that initializing
SDL replaces the SIGTERM handler to receive the event in the event loop,
so pressing Ctrl+C during step 5 would not work (since it blocks the
event loop).
But this is not so important; let's parallelize the SDL initialization
with the app_process execution (we'll just add a timeout to the
connection):
HOST DEVICE
listen on port | |
push/start the server |----------------->||app_process loads the jar
init SDL || ||
|| ||
|| ||
|| ||
|| ||
|| ||
accept the connection . ||
. X execution of our java main
connection accepted |<-----------------| connect to the host
init window/renderer | |
display frames |<-----------------| send frames
|<-----------------|
In addition, show the window only once the first frame is available to
avoid flickering (opening a black window for 100~200ms).
Note: the window and renderer are initialized after the connection is
accepted because they use the device information received from the
device.
2018-02-09 20:50:54 +08:00
|
|
|
// show the window
|
|
|
|
void screen_show_window(struct screen *screen);
|
|
|
|
|
2018-02-08 18:14:13 +08:00
|
|
|
// destroy window, renderer and texture (if any)
|
|
|
|
void screen_destroy(struct screen *screen);
|
|
|
|
|
2018-02-09 18:14:47 +08:00
|
|
|
// resize if necessary and write the rendered frame into the texture
|
2019-03-02 22:16:55 +08:00
|
|
|
SDL_bool screen_update_frame(struct screen *screen, struct video_buffer *vb);
|
2018-02-08 18:14:13 +08:00
|
|
|
|
|
|
|
// render the texture to the renderer
|
|
|
|
void screen_render(struct screen *screen);
|
|
|
|
|
|
|
|
// switch the fullscreen mode
|
|
|
|
void screen_switch_fullscreen(struct screen *screen);
|
|
|
|
|
|
|
|
// resize window to optimal size (remove black borders)
|
|
|
|
void screen_resize_to_fit(struct screen *screen);
|
|
|
|
|
|
|
|
// resize window to 1:1 (pixel-perfect)
|
|
|
|
void screen_resize_to_pixel_perfect(struct screen *screen);
|
|
|
|
|
|
|
|
#endif
|