diff --git a/renderers/video_renderer.c b/renderers/video_renderer.c index fbe2540..dcc5982 100644 --- a/renderers/video_renderer.c +++ b/renderers/video_renderer.c @@ -23,7 +23,6 @@ #include #include #include "video_renderer.h" -#include "../lib/raop.h" #define SECOND_IN_NSECS 1000000000UL #define SECOND_IN_MICROSECS 1000000 @@ -46,7 +45,6 @@ static bool hls_video = false; static bool use_x11 = false; #endif static bool logger_debug = false; -static bool video_terminate = false; static gint64 hls_requested_start_position = 0; static gint64 hls_seek_start = 0; static gint64 hls_seek_end = 0; @@ -77,7 +75,6 @@ typedef enum { } GstPlayFlags; #define NCODECS 3 /* renderers for h264,h265, and jpeg images */ -static raop_t * raop = NULL; struct video_renderer_s { GstElement *appsrc, *pipeline; @@ -86,7 +83,7 @@ struct video_renderer_s { bool autovideo; int id; char *uri; - gboolean terminate; + gboolean eos; gint64 duration; gint buffering_level; #ifdef X_DISPLAY_FIX @@ -232,13 +229,11 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, video GstCaps *caps = NULL; bool rtp = (bool) strlen(rtp_pipeline); hls_video = (uri != NULL); - raop = NULL; /* videosink choices that are auto */ auto_videosink = (strstr(videosink, "autovideosink") || strstr(videosink, "fpsdisplaysink")); logger = render_logger; logger_debug = (logger_get_level(logger) >= LOGGER_DEBUG); - video_terminate = false; hls_seek_enabled = FALSE; hls_playing = FALSE; hls_seek_start = -1; @@ -284,6 +279,7 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, video renderer_type[i]->bus = NULL; renderer_type[i]->appsrc = NULL; renderer_type[i]->uri = NULL; + renderer_type[i]->eos = FALSE; if (hls_video) { renderer_type[i]->uri = (char *) calloc(strlen(uri) + 1, sizeof(char)); memcpy(renderer_type[i]->uri, uri, strlen(uri)); @@ -479,11 +475,10 @@ void video_renderer_resume() { } } -void video_renderer_start( void * opaque) { +void video_renderer_start() { GstState state; const gchar *state_name; if (hls_video) { - raop = (raop_t *) opaque; g_object_set (G_OBJECT (renderer->pipeline), "uri", renderer->uri, NULL); gst_element_set_state (renderer->pipeline, GST_STATE_PAUSED); gst_element_get_state(renderer->pipeline, &state, NULL, 1000 * GST_MSECOND); @@ -492,7 +487,6 @@ void video_renderer_start( void * opaque) { return; } /* when not hls, start both h264 and h265 pipelines; will shut down the "wrong" one when we know the codec */ - raop = NULL; for (int i = 0; i < n_renderers; i++) { gst_element_set_state (renderer_type[i]->pipeline, GST_STATE_PAUSED); gst_element_get_state(renderer_type[i]->pipeline, &state, NULL, 1000 * GST_MSECOND); @@ -867,7 +861,6 @@ static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *m if (!hls_video) { gst_bus_set_flushing(bus, TRUE); gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_READY); - renderer_type[type]->terminate = TRUE; g_main_loop_quit( (GMainLoop *) loop); } break; @@ -878,8 +871,7 @@ static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *m if (hls_video) { gst_bus_set_flushing(bus, TRUE); gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_READY); - renderer_type[type]->terminate = TRUE; - g_main_loop_quit( (GMainLoop *) loop); + renderer_type[type]->eos = TRUE; } break; case GST_MESSAGE_STATE_CHANGED: @@ -1021,20 +1013,6 @@ int video_renderer_choose_codec (bool video_is_jpeg, bool video_is_h265) { return 0; } -unsigned int video_reset_callback(void * loop) { - if (video_terminate) { - video_terminate = false; - if (renderer->appsrc) { - gst_app_src_end_of_stream (GST_APP_SRC(renderer->appsrc)); - } - gboolean flushing = TRUE; - gst_bus_set_flushing(renderer->bus, flushing); - gst_element_set_state (renderer->pipeline, GST_STATE_NULL); - g_main_loop_quit( (GMainLoop *) loop); - } - return (unsigned int) TRUE; -} - bool video_get_playback_info(double *duration, double *position, float *rate, bool *buffer_empty, bool *buffer_full) { gint64 pos = 0; GstState state; @@ -1107,3 +1085,11 @@ unsigned int video_renderer_listen(void *loop, int id) { return (unsigned int) gst_bus_add_watch(renderer_type[id]->bus,(GstBusFunc) gstreamer_video_pipeline_bus_callback, (gpointer) loop); } + +bool video_renderer_eos_watch() { + if (hls_video && renderer->eos) { + renderer->eos = FALSE; + return true; + } + return false; +} diff --git a/renderers/video_renderer.h b/renderers/video_renderer.h index 9458250..ab4618e 100644 --- a/renderers/video_renderer.h +++ b/renderers/video_renderer.h @@ -47,11 +47,11 @@ typedef enum videoflip_e { typedef struct video_renderer_s video_renderer_t; - void video_renderer_init (logger_t *logger, const char *server_name, videoflip_t videoflip[2], const char *parser, const char *rtp_pipeline, +void video_renderer_init (logger_t *logger, const char *server_name, videoflip_t videoflip[2], const char *parser, const char *rtp_pipeline, const char *decoder, const char *converter, const char *videosink, const char *videosink_options, bool initial_fullscreen, bool video_sync, bool h265_support, bool coverart_support, guint playbin_version, const char *uri); -void video_renderer_start (void *raop); +void video_renderer_start (); void video_renderer_stop (); void video_renderer_pause (); void video_renderer_hls_ready (); @@ -60,6 +60,7 @@ void video_renderer_set_start(float position); void video_renderer_resume (); int video_renderer_cycle (); bool video_renderer_is_paused(); +bool video_renderer_eos_watch(); uint64_t video_renderer_render_buffer (unsigned char* data, int *data_len, int *nal_count, uint64_t *ntp_time); void video_renderer_display_jpeg(const void *data, int *data_len); void video_renderer_flush (); @@ -70,7 +71,7 @@ bool waiting_for_x11_window(); bool video_get_playback_info(double *duration, double *position, float *rate, bool *buffer_empty, bool *buffer_full); int video_renderer_choose_codec (bool video_is_jpeg, bool video_is_h265); unsigned int video_renderer_listen(void *loop, int id); -unsigned int video_reset_callback(void *loop); +bool video_renderer_eos_watch(); #ifdef __cplusplus } #endif diff --git a/uxplay.cpp b/uxplay.cpp index c06e23e..5e4dfed 100644 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -178,6 +178,7 @@ static bool hls_support = false; static std::string lang = ""; static std::string url = ""; static guint gst_x11_window_id = 0; +static guint video_eos_watch_id = 0; static guint progress_id = 0; static guint gst_hls_position_id = 0; static bool preserve_connections = false; @@ -633,6 +634,14 @@ static gboolean progress_callback (gpointer loop) { } } +static gboolean video_eos_watch_callback (gpointer loop) { + if (video_renderer_eos_watch()) { + /* HLS video has sent EOS */ + LOGI("hls video has sent EOS"); + } + return TRUE; +} + #define MAX_VIDEO_RENDERERS 3 #define MAX_AUDIO_RENDERERS 2 static void main_loop() { @@ -657,10 +666,12 @@ static void main_loop() { n_video_renderers++; } /* renderer[0] : h264 video; followed by h265 video (optional) and jpeg (optional) */ - gst_x11_window_id = 0; + gst_x11_window_id = 0; + video_eos_watch_id = 0; } else { /* hls video will be rendered: renderer[0] : hls */ url.erase(); + video_eos_watch_id = g_timeout_add(100, (GSourceFunc) video_eos_watch_callback, (gpointer) loop); gst_x11_window_id = g_timeout_add(100, (GSourceFunc) x11_window_callback, (gpointer) loop); } g_assert(n_video_renderers <= MAX_VIDEO_RENDERERS); @@ -685,7 +696,6 @@ static void main_loop() { missed_feedback = 0; guint feedback_watch_id = g_timeout_add_seconds(1, (GSourceFunc) feedback_callback, (gpointer) loop); guint reset_watch_id = g_timeout_add(100, (GSourceFunc) reset_callback, (gpointer) loop); - guint video_reset_watch_id = g_timeout_add(100, (GSourceFunc) video_reset_callback, (gpointer) loop); #ifdef _WIN32 gmainloop = loop; @@ -717,9 +727,10 @@ static void main_loop() { if (gst_audio_bus_watch_id[i] > 0) g_source_remove(gst_audio_bus_watch_id[i]); } if (gst_x11_window_id > 0) g_source_remove(gst_x11_window_id); + if (video_eos_watch_id > 0) g_source_remove(video_eos_watch_id); if (reset_watch_id > 0) g_source_remove(reset_watch_id); if (progress_id > 0) g_source_remove(progress_id); - if (video_reset_watch_id > 0) g_source_remove(video_reset_watch_id); + if (video_eos_watch_id > 0) g_source_remove(video_eos_watch_id); if (feedback_watch_id > 0) g_source_remove(feedback_watch_id); g_main_loop_unref(loop); } @@ -2994,7 +3005,7 @@ int main (int argc, char *argv[]) { video_decoder.c_str(), video_converter.c_str(), videosink.c_str(), videosink_options.c_str(), fullscreen, video_sync, h265_support, render_coverart, playbin_version, NULL); - video_renderer_start(NULL); + video_renderer_start(); #ifdef __OpenBSD__ } else { if (pledge("stdio rpath wpath cpath inet unix prot_exec", NULL) == -1) { @@ -3096,7 +3107,7 @@ int main (int argc, char *argv[]) { video_decoder.c_str(), video_converter.c_str(), videosink.c_str(), videosink_options.c_str(), fullscreen, video_sync, h265_support, render_coverart, playbin_version, uri); - video_renderer_start((void *) raop); + video_renderer_start(); } if (reset_httpd) { unsigned short port = raop_get_port(raop);