First commit with working display

This commit is contained in:
Ricardo LAP
2026-09-13 20:50:51 +00:00
parent a83af259b3
commit c54c68c899
6690 changed files with 1093387 additions and 2 deletions

View File

@@ -0,0 +1,8 @@
.. example_heading: GStreamer
Loads a video from the internet using the gstreamer widget
----------------------------------------------------------
.. lv_example:: libs/gstreamer/lv_example_gstreamer_1
:language: c

View File

@@ -0,0 +1,39 @@
/**
* @file lv_example_gstreamer.h
*
*/
#ifndef LV_EXAMPLE_GSTREAMER_H
#define LV_EXAMPLE_GSTREAMER_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_gstreamer_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_GSTREAMER_H*/

View File

@@ -0,0 +1,237 @@
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_GSTREAMER
typedef struct {
lv_obj_t * streamer;
lv_obj_t * pp_button;
lv_obj_t * button_label;
lv_obj_t * position_label;
lv_obj_t * duration_label;
lv_subject_t position_subject;
} event_data_t;
static void volume_setter_create(event_data_t * event_data);
static void control_bar_create(event_data_t * event_data);
static void update_duration_label(lv_obj_t * label, uint32_t duration);
static void volume_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
static void update_position_slider(lv_timer_t * timer);
static void play_pause_pressed(lv_event_t * e);
static void stream_state_changed(lv_event_t * e);
/**
* Loads a video from the internet using the gstreamer widget
*/
void lv_example_gstreamer_1(void)
{
static event_data_t event_data;
event_data.streamer = lv_gstreamer_create(lv_screen_active());
/* the gstreamer widget inherits the `lv_image` widget,
* meaning you can also provide it lv_image functions, like
lv_image_set_scale(event_data.streamer, 100);
lv_image_set_rotation(event_data.streamer, 100);
*/
/* Set the current src of the streamer.
* Using the `URI` "factory", we can
* specify various URI schemes as media sources including local files (file://),
* web streams (http://, https://), RTSP streams (rtsp://), UDP streams (udp://),
* and many others. GStreamer's uridecodebin automatically selects the appropriate
* source element and decoder based on the URI scheme and media format. */
lv_gstreamer_set_src(event_data.streamer, LV_GSTREAMER_FACTORY_URI_DECODE, LV_GSTREAMER_PROPERTY_URI_DECODE,
"https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm");
lv_obj_center(event_data.streamer);
/* Create a slider to modify the stream volume and a label to visualize the current value */
volume_setter_create(&event_data);
/* Create a slider to see the position in the stream with 2 text label on each side
* One for the current position in the stream and the other for the total duration of the stream
* Also add a pause/play button*/
control_bar_create(&event_data);
/* The LV_EVENT_STATE_CHANGED will fire when the stream is ready at that point we can query the stream
* information like its resolution and duration. See `streamer_ready` */
lv_obj_add_event_cb(event_data.streamer, stream_state_changed, LV_EVENT_STATE_CHANGED, &event_data);
/* Play the stream immediately */
lv_gstreamer_play(event_data.streamer);
/* Create a timer that will update the slider position based on the stream position
* Make it 3 times faster than the refresh rate for a smoother effect */
lv_timer_create(update_position_slider, LV_DEF_REFR_PERIOD, &event_data);
}
static void volume_setter_create(event_data_t * event_data)
{
lv_obj_t * cont = lv_obj_create(lv_screen_active());
lv_obj_remove_style_all(cont);
lv_obj_set_style_pad_all(cont, 8, 0);
lv_obj_set_style_pad_gap(cont, 8, 0);
lv_obj_set_style_radius(cont, 8, 0);
lv_obj_set_style_bg_color(cont, lv_color_white(), 0);
lv_obj_set_style_bg_opa(cont, LV_OPA_70, 0);
lv_obj_set_size(cont, 40, lv_pct(60));
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_align(cont, LV_ALIGN_RIGHT_MID, -8, -40);
lv_obj_t * volume_slider = lv_slider_create(cont);
lv_obj_set_size(volume_slider, 13, LV_PCT(50));
lv_obj_set_flex_grow(volume_slider, 1);
lv_obj_t * volume_label = lv_label_create(cont);
lv_obj_set_style_text_align(volume_label, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_set_width(volume_label, 50);
/* We use `lv_subject` to simplify binding the data between multiple objects.
* Here the data is shared between the slider, the label and the gstreamer widgets */
static lv_subject_t volume_subject;
lv_subject_init_int(&volume_subject, 50);
lv_subject_add_observer_obj(&volume_subject, volume_observer_cb, event_data->streamer, NULL);
lv_slider_bind_value(volume_slider, &volume_subject);
lv_label_bind_text(volume_label, &volume_subject, LV_SYMBOL_VOLUME_MID "\n%3" LV_PRId32 "%%");
}
static void control_bar_create(event_data_t * event_data)
{
lv_subject_init_int(&event_data->position_subject, 0);
lv_obj_t * cont = lv_obj_create(lv_screen_active());
lv_obj_remove_style_all(cont);
lv_obj_set_style_pad_all(cont, 8, 0);
lv_obj_set_style_margin_hor(cont, 8, 0);
lv_obj_set_style_pad_gap(cont, 8, 0);
lv_obj_set_style_radius(cont, 8, 0);
lv_obj_set_style_bg_color(cont, lv_color_white(), 0);
lv_obj_set_style_bg_opa(cont, LV_OPA_70, 0);
lv_obj_set_size(cont, lv_pct(100), LV_SIZE_CONTENT);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_align(cont, LV_ALIGN_BOTTOM_MID, 0, -10);
event_data->position_label = lv_label_create(cont);
lv_obj_set_width(event_data->position_label, 80);
lv_label_set_text_static(event_data->position_label, "0:00:000");
/* Create a button a button to play/pause the stream */
event_data->pp_button = lv_button_create(cont);
lv_obj_center(event_data->pp_button);
lv_obj_add_event_cb(event_data->pp_button, play_pause_pressed, LV_EVENT_CLICKED, event_data);
event_data->button_label = lv_label_create(event_data->pp_button);
lv_label_set_text_static(event_data->button_label, LV_SYMBOL_PAUSE);
lv_obj_t * position_slider = lv_bar_create(cont);
lv_bar_set_range(position_slider, 0, 1000);
lv_obj_set_flex_grow(position_slider, 1);
lv_slider_bind_value(position_slider, &event_data->position_subject);
event_data->duration_label = lv_label_create(cont);
lv_obj_set_width(event_data->duration_label, 80);
lv_label_set_text_static(event_data->duration_label, "0:00:000");
lv_obj_set_style_text_align(event_data->duration_label, LV_TEXT_ALIGN_RIGHT, 0);
}
static void update_duration_label(lv_obj_t * label, uint32_t duration)
{
const uint32_t minutes = duration / 60000;
const uint32_t seconds = (duration / 1000) % 60;
const uint32_t milliseconds = duration % 1000;
lv_label_set_text_fmt(label, "%" LV_PRIu32 ":%02" LV_PRIu32 ":%03" LV_PRIu32, minutes, seconds, milliseconds);
}
static void volume_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
{
lv_obj_t * streamer = lv_observer_get_target_obj(observer);
int32_t volume = lv_subject_get_int(subject);
LV_LOG_USER("Setting volume %" PRId32, volume);
lv_gstreamer_set_volume(streamer, (uint8_t)volume);
}
static void update_position_slider(lv_timer_t * timer)
{
event_data_t * event_data = (event_data_t *)lv_timer_get_user_data(timer);
uint32_t duration = lv_gstreamer_get_duration(event_data->streamer);
uint32_t position = lv_gstreamer_get_position(event_data->streamer);
int32_t position_perc = lv_map(position, 0, duration, 0, 1000);
lv_subject_set_int(&event_data->position_subject, position_perc);
update_duration_label(event_data->position_label, position);
}
static void play_pause_pressed(lv_event_t * e)
{
event_data_t * event_data = (event_data_t *)lv_event_get_user_data(e);
if(lv_streq(lv_label_get_text(event_data->button_label), LV_SYMBOL_REFRESH)) {
lv_gstreamer_set_position(event_data->streamer, 0);
lv_gstreamer_play(event_data->streamer);
}
else if(lv_streq(lv_label_get_text(event_data->button_label), LV_SYMBOL_PLAY)) {
lv_gstreamer_play(event_data->streamer);
}
else {
lv_gstreamer_pause(event_data->streamer);
}
}
static void stream_state_changed(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
event_data_t * event_data = (event_data_t *)lv_event_get_user_data(e);
lv_obj_t * streamer = event_data->streamer;
if(code != LV_EVENT_STATE_CHANGED) {
return;
}
lv_gstreamer_stream_state_t stream_state = lv_gstreamer_get_stream_state(e);
switch(stream_state) {
case LV_GSTREAMER_STREAM_STATE_START: {
uint32_t duration = lv_gstreamer_get_duration(streamer);
LV_LOG_USER("Stream is starting");
LV_LOG_USER("\tStream resolution %" LV_PRId32 "x%" LV_PRId32, lv_image_get_src_width(streamer),
lv_image_get_src_height(streamer));
LV_LOG_USER("\tStream duration %" LV_PRIu32, duration);
update_duration_label(event_data->duration_label, duration);
break;
}
case LV_GSTREAMER_STREAM_STATE_END:
LV_LOG_USER("Stream is over");
lv_label_set_text_static(event_data->button_label, LV_SYMBOL_REFRESH);
break;
case LV_GSTREAMER_STREAM_STATE_PLAY:
lv_label_set_text_static(event_data->button_label, LV_SYMBOL_PAUSE);
break;
case LV_GSTREAMER_STREAM_STATE_PAUSE:
case LV_GSTREAMER_STREAM_STATE_STOP:
lv_label_set_text_static(event_data->button_label, LV_SYMBOL_PLAY);
break;
}
}
#else
void lv_example_gstreamer_1(void)
{
/*TODO
*fallback for online examples*/
lv_obj_t * label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "GStreamer web support is coming soon");
lv_obj_center(label);
}
#endif
#endif