usb: add video capture through the fxlink protocol

This commit is contained in:
Lephe 2021-08-11 01:12:00 +02:00
parent 8713d2644f
commit d3a2cf07a0
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
8 changed files with 96 additions and 12 deletions

View File

@ -59,6 +59,7 @@ set(SOURCES_COMMON
src/render/dprint.c
src/render/drect_border.c
src/render/dtext.c
src/render/dupdate_hook.c
src/render/dvline.c
src/render/topti.c
src/rtc/rtc.c

View File

@ -14,6 +14,7 @@ extern "C" {
#endif
#include <gint/defs/types.h>
#include <gint/defs/call.h>
/* Platform-specific functions include VRAM management and the definition of
the color_t type. */
@ -62,6 +63,25 @@ extern "C" {
fx-CG 50: 11 ms */
void dupdate(void);
/* dupdate_set_hook(): Define a function to be called after each dupdate()
This functions configures the update hook, which is called after each
dupdate() has sent VRAM to the display (but before VRAMs are switched when
triple-buffering is used on fx-CG 50).
The hook is mostly useful to send a copy of the frame to another medium,
typically through a USB connection to a projector-style application. See
usb_fxlink_videocapture() in <gint/usb-ff-bulk.h> for an example.
The function is an indirect call; create one with the GINT_CALL() macro from
<gint/defs/call.h>. Pass GINT_CALL_NULL to disable the feature.
@function Indirect call to perform after each dupdate(). */
void dupdate_set_hook(gint_call_t function);
/* dupdate_get_hook(): Get a copy of the dupdate() hook */
gint_call_t dupdate_get_hook(void);
//---
// Area rendering functions
//---

View File

@ -97,8 +97,8 @@ typedef struct
Returns false if the parameters are invalid or don't fit, in this case the
contents of the header are unchanged. */
bool usb_fxlink_fill_header(usb_fxlink_header_t *header, char *application,
char *type, uint32_t data_size);
bool usb_fxlink_fill_header(usb_fxlink_header_t *header,
char const *application, char const *type, uint32_t data_size);
//---
// Short functions for fxlink built-in types
@ -168,6 +168,23 @@ void usb_fxlink_screenshot_gray(bool onscreen);
and size allow, and 1 byte otherwise. If size is 0, strlen(text) is used. */
void usb_fxlink_text(char const *text, int size);
/* usb_fxlink_videocapture(): Send a frame for a video recording
This function is essentially the same as usb_fxlink_screenshot(). It sends a
capture of the VRAM to fxlink but uses the "video" type, which fxlink
displays in real-time or saves as a video file. The meaning of the onscreen
setting is identical to usb_fxlink_screenshot().
This function can be called with onscreen=false as a dupdate() hook to
automatically send new frames to fxlink. */
void usb_fxlink_videocapture(bool onscreen);
#ifdef FX9860G
/* usb_fxlink_videocapture_gray(): Send a gray frame for a video recording
Like usb_fxlink_videocapture(), but uses VRAM data from the gray engine. */
void usb_fxlink_videocapture_gray(bool onscreen);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -7,6 +7,9 @@ void dupdate(void)
{
r61524_display(gint_vram, 0, 224, R61524_DMA);
gint_call_t hook = dupdate_get_hook();
if(hook.function) gint_call(hook);
/* The DMA is still running, so we need to switch VRAMs to avoid
overwriting the data which is about to be sent. */
dvram_switch();

View File

@ -11,16 +11,23 @@ uint32_t *gint_vram = fx_vram;
/* The current rendering mode */
struct rendering_mode const *dmode = NULL;
/* dupdate() - push the video RAM to the display driver */
/* dupdate(): Push the video RAM to the display driver */
void dupdate(void)
{
bool run_default = true;
if(dmode && dmode->dupdate)
{
/* Call the overridden dupdate(), but continue if itreturns
/* Call the overridden dupdate(), but continue if it returns
non-zero (this is used when stopping the gray engine) */
int rc = dmode->dupdate();
if(rc == 0) return;
run_default = (rc != 0);
}
if(run_default)
{
t6k11_display(gint_vram, 0, 64, 16);
}
t6k11_display(gint_vram, 0, 64, 16);
gint_call_t hook = dupdate_get_hook();
if(hook.function) gint_call(hook);
}

16
src/render/dupdate_hook.c Normal file
View File

@ -0,0 +1,16 @@
#include <gint/display.h>
/* Hook to be called after each dupdate(). */
static gint_call_t hook = GINT_CALL_NULL;
/* dupdate_set_hook(): Define a function to be called after each dupdate() */
void dupdate_set_hook(gint_call_t function)
{
hook = function;
}
/* dupdate_get_hook(): Get a copy of the dupdate() hook */
gint_call_t dupdate_get_hook(void)
{
return hook;
}

View File

@ -5,7 +5,7 @@
#include <gint/display.h>
#include <gint/gray.h>
void usb_fxlink_screenshot_gray(GUNUSED bool onscreen)
static void capture_vram_gray(GUNUSED bool onscreen, char const *type)
{
uint32_t *light, *dark;
if(onscreen) dgray_getscreen(&light, &dark);
@ -14,7 +14,7 @@ void usb_fxlink_screenshot_gray(GUNUSED bool onscreen)
usb_fxlink_header_t header;
usb_fxlink_image_t subheader;
usb_fxlink_fill_header(&header, "fxlink", "image",
usb_fxlink_fill_header(&header, "fxlink", type,
2048 + sizeof subheader);
subheader.width = htole32(DWIDTH);
@ -29,4 +29,14 @@ void usb_fxlink_screenshot_gray(GUNUSED bool onscreen)
usb_commit_sync(pipe);
}
void usb_fxlink_screenshot_gray(bool onscreen)
{
capture_vram_gray(onscreen, "image");
}
void usb_fxlink_videocapture_gray(bool onscreen)
{
capture_vram_gray(onscreen, "video");
}
#endif /* FX9860G */

View File

@ -60,8 +60,8 @@ int usb_ff_bulk_output(void)
// fxlink protocol
//---
bool usb_fxlink_fill_header(usb_fxlink_header_t *header, char *application,
char *type, uint32_t data_size)
bool usb_fxlink_fill_header(usb_fxlink_header_t *header,
char const *application, char const *type, uint32_t data_size)
{
if(strlen(application) > 16 || strlen(type) > 16) return false;
@ -77,7 +77,7 @@ bool usb_fxlink_fill_header(usb_fxlink_header_t *header, char *application,
return true;
}
void usb_fxlink_screenshot(GUNUSED bool onscreen)
static void capture_vram(GUNUSED bool onscreen, char const *type)
{
void *source = gint_vram;
int size, format;
@ -100,7 +100,7 @@ void usb_fxlink_screenshot(GUNUSED bool onscreen)
usb_fxlink_header_t header;
usb_fxlink_image_t subheader;
usb_fxlink_fill_header(&header, "fxlink", "image",
usb_fxlink_fill_header(&header, "fxlink", type,
size + sizeof subheader);
subheader.width = htole32(DWIDTH);
@ -114,6 +114,11 @@ void usb_fxlink_screenshot(GUNUSED bool onscreen)
usb_commit_sync(pipe);
}
void usb_fxlink_screenshot(bool onscreen)
{
capture_vram(onscreen, "image");
}
void usb_fxlink_text(char const *text, int size)
{
if(size == 0) size = strlen(text);
@ -130,3 +135,8 @@ void usb_fxlink_text(char const *text, int size)
usb_write_sync(pipe, text, size, unit_size, false);
usb_commit_sync(pipe);
}
void usb_fxlink_videocapture(bool onscreen)
{
capture_vram(onscreen, "video");
}