various hls improvements (seek to start_pos

This commit is contained in:
F. Duncanh
2025-12-18 13:08:23 -05:00
parent 59568e3bda
commit 382b78251b
5 changed files with 61 additions and 46 deletions

View File

@@ -400,8 +400,8 @@ http_handler_playback_info(raop_conn_t *conn, http_request_t *request, http_resp
playback_info.num_seekable_time_ranges = 1; playback_info.num_seekable_time_ranges = 1;
time_range_t time_ranges_seekable[1]; time_range_t time_ranges_seekable[1];
time_ranges_seekable[0].start = 0.0; time_ranges_seekable[0].start = playback_info.seek_start;
time_ranges_seekable[0].duration = playback_info.position; time_ranges_seekable[0].duration = playback_info.seek_duration;
playback_info.seekableTimeRanges = (void *) &time_ranges_seekable; playback_info.seekableTimeRanges = (void *) &time_ranges_seekable;
*response_datalen = create_playback_info_plist_xml(&playback_info, response_data); *response_datalen = create_playback_info_plist_xml(&playback_info, response_data);
@@ -727,7 +727,6 @@ delete_short_playlist(raop_t *raop, int id) {
static void static void
http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *response, http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *response,
char **response_data, int *response_datalen) { char **response_data, int *response_datalen) {
raop_t *raop = conn->raop; raop_t *raop = conn->raop;
char* playback_location = NULL; char* playback_location = NULL;
char* client_proc_name = NULL; char* client_proc_name = NULL;
@@ -785,10 +784,12 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
/* check if playlist is already downloaded and stored (may have been interruoted by advertisements ) */ /* check if playlist is already downloaded and stored (may have been interruoted by advertisements ) */
if (id >= 0) { if (id >= 0) {
printf("use: airplay_video[%d] %p %s %s\n", id, raop->airplay_video[id], playback_uuid, get_playback_uuid(raop->airplay_video[id])); //printf("====use EXISTING airplay_video[%d] %p %s %s\n", id, raop->airplay_video[id], playback_uuid, get_playback_uuid(raop->airplay_video[id]));
plist_mem_free(playback_uuid);
plist_free(req_root_node);
int current_video = raop->current_video; int current_video = raop->current_video;
if (current_video >= 0 && current_video != id) { if (current_video >= 0 && current_video != id) {
delete_short_playlist(raop, current_video); delete_short_playlist(raop, current_video);
} }
raop->current_video = id; raop->current_video = id;
airplay_video = hls_get_current_video(raop); airplay_video = hls_get_current_video(raop);
@@ -796,11 +797,10 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
set_apple_session_id(airplay_video, apple_session_id, strlen(apple_session_id)); set_apple_session_id(airplay_video, apple_session_id, strlen(apple_session_id));
float resume_pos = get_resume_position_seconds(airplay_video); float resume_pos = get_resume_position_seconds(airplay_video);
float start_pos = get_start_position_seconds(airplay_video); float start_pos = get_start_position_seconds(airplay_video);
//printf("========= %f ============call on_video_play===== %f ==========\n", start_pos, resume_pos);
raop->callbacks.on_video_play(raop->callbacks.cls, raop->callbacks.on_video_play(raop->callbacks.cls,
get_playback_location(airplay_video), get_playback_location(airplay_video),
resume_pos > start_pos ? resume_pos : start_pos); resume_pos > start_pos ? resume_pos : start_pos);
plist_mem_free(playback_uuid);
plist_free(req_root_node);
return; return;
} }
@@ -836,7 +836,6 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
set_playback_uuid(airplay_video, playback_uuid, strlen(playback_uuid)); set_playback_uuid(airplay_video, playback_uuid, strlen(playback_uuid));
plist_mem_free (playback_uuid); plist_mem_free (playback_uuid);
count++; count++;
printf("created new airplay_video %p %s\n\n", airplay_video, get_playback_uuid(airplay_video));
} else { } else {
logger_log(raop->logger, LOGGER_ERR, "failed to allocate airplay_video[%d]\n", id); logger_log(raop->logger, LOGGER_ERR, "failed to allocate airplay_video[%d]\n", id);
exit(-1); exit(-1);
@@ -944,7 +943,6 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
raop_t *raop = conn->raop; raop_t *raop = conn->raop;
if (raop->current_video == -1) { if (raop->current_video == -1) {
logger_log(raop->logger, LOGGER_ERR,"airplay_video playlist not found"); logger_log(raop->logger, LOGGER_ERR,"airplay_video playlist not found");
*response_datalen = 0;
http_response_init(response, "HTTP/1.1", 404, "Not Found"); http_response_init(response, "HTTP/1.1", 404, "Not Found");
return; return;
} }
@@ -973,7 +971,6 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
*response_datalen = (int ) len; *response_datalen = (int ) len;
} else { } else {
logger_log(raop->logger, LOGGER_ERR,"requested master playlist %s not found", url); logger_log(raop->logger, LOGGER_ERR,"requested master playlist %s not found", url);
*response_datalen = 0;
} }
} else { } else {
@@ -988,7 +985,6 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
"Requested media_playlist %s has %5d chunks, total duration %9.3f secs", url, chunks, duration); "Requested media_playlist %s has %5d chunks, total duration %9.3f secs", url, chunks, duration);
} else { } else {
logger_log(raop->logger, LOGGER_ERR,"requested media playlist %s not found", url); logger_log(raop->logger, LOGGER_ERR,"requested media playlist %s not found", url);
*response_datalen = 0;
} }
} }

View File

@@ -41,6 +41,8 @@ typedef struct playback_info_s {
uint32_t stallcount; uint32_t stallcount;
double duration; double duration;
double position; double position;
double seek_start;
double seek_duration;
float rate; float rate;
bool ready_to_play; bool ready_to_play;
bool playback_buffer_empty; bool playback_buffer_empty;

View File

@@ -732,7 +732,20 @@ static void get_stream_status_name(GstStreamStatusType type, char *name, size_t
return; return;
} }
} }
static void hls_video_seek_to_start_position(GstElement *pipeline) {
if (hls_requested_start_position && hls_seek_enabled && hls_requested_start_position >= hls_seek_start
&& hls_requested_start_position <= hls_seek_end) {
g_print("***************** seek to hls_requested_start_position %" GST_TIME_FORMAT "\n", GST_TIME_ARGS(hls_requested_start_position));
if (gst_element_seek_simple (pipeline, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, hls_requested_start_position)) {
hls_requested_start_position = 0;
} else {
g_print("*** seek to requested_start_position failed\n");
}
}
}
static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *message, void *loop) { static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *message, void *loop) {
GstState old_state, new_state; GstState old_state, new_state;
const gchar no_state[] = ""; const gchar no_state[] = "";
@@ -764,6 +777,14 @@ static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *m
video_renderer_t *renderer = renderer_type[type]; video_renderer_t *renderer = renderer_type[type];
gint64 pos = -1;
if (hls_video) {
gst_element_query_position (renderer_type[type]->pipeline, GST_FORMAT_TIME, &pos);
if (hls_requested_start_position && pos >= hls_requested_start_position) {
hls_requested_start_position = 0;
}
}
if (logger_debug) { if (logger_debug) {
gchar *name = NULL; gchar *name = NULL;
GstElement *element = NULL; GstElement *element = NULL;
@@ -776,10 +797,6 @@ static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *m
old_state_name = name; old_state_name = name;
new_state_name = type_name; new_state_name = type_name;
} }
gint64 pos = -1;
if (hls_video) {
gst_element_query_position (renderer->pipeline, GST_FORMAT_TIME, &pos);
}
if (GST_CLOCK_TIME_IS_VALID(pos)) { if (GST_CLOCK_TIME_IS_VALID(pos)) {
g_print("GStreamer %s bus message %s %s %s %s; position: %" GST_TIME_FORMAT "\n" ,renderer->codec, g_print("GStreamer %s bus message %s %s %s %s; position: %" GST_TIME_FORMAT "\n" ,renderer->codec,
GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message), old_state_name, new_state_name, GST_TIME_ARGS(pos)); GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message), old_state_name, new_state_name, GST_TIME_ARGS(pos));
@@ -792,28 +809,12 @@ static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *m
} }
} }
/* monitor hls video position until seek to hls_start_position is achieved */ if (hls_video && !GST_CLOCK_TIME_IS_VALID(hls_duration)) {
if (hls_video && hls_requested_start_position) { gst_element_query_duration (renderer->pipeline, GST_FORMAT_TIME, &hls_duration);
if (strstr(GST_MESSAGE_SRC_NAME(message), "sink")) { }
gint64 pos = -1;
if (!GST_CLOCK_TIME_IS_VALID(hls_duration)) { if (hls_requested_start_position && hls_seek_enabled) {
gst_element_query_duration (renderer->pipeline, GST_FORMAT_TIME, &hls_duration); hls_video_seek_to_start_position(renderer->pipeline);
}
gst_element_query_position (renderer->pipeline, GST_FORMAT_TIME, &pos);
//g_print("HLS position %" GST_TIME_FORMAT " requested_start_position %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT " %s\n",
// GST_TIME_ARGS(pos), GST_TIME_ARGS(hls_requested_start_position), GST_TIME_ARGS(hls_duration),
// (hls_seek_enabled ? "seek enabled" : "seek not enabled"));
if (pos > hls_requested_start_position) {
hls_requested_start_position = 0;
}
if ( hls_requested_start_position && pos < hls_requested_start_position && hls_seek_enabled) {
g_print("***************** seek to hls_requested_start_position %" GST_TIME_FORMAT "\n", GST_TIME_ARGS(hls_requested_start_position));
if (gst_element_seek_simple (renderer->pipeline, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, hls_requested_start_position)) {
hls_requested_start_position = 0;
}
}
}
} }
switch (GST_MESSAGE_TYPE (message)) { switch (GST_MESSAGE_TYPE (message)) {
@@ -881,16 +882,18 @@ static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *m
} }
break; break;
case GST_MESSAGE_STATE_CHANGED: case GST_MESSAGE_STATE_CHANGED:
if (hls_video && logger_debug && strstr(GST_MESSAGE_SRC_NAME(message), "hls-playbin")) { if (hls_video && strstr(GST_MESSAGE_SRC_NAME(message), "hls-playbin")) {
GstState old_state, new_state; GstState old_state, new_state;
gst_message_parse_state_changed (message, &old_state, &new_state, NULL); gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
if (logger_debug) {
g_print ("****** hls_playbin: Element %s changed state from %s to %s.\n", GST_OBJECT_NAME (message->src), g_print ("****** hls_playbin: Element %s changed state from %s to %s.\n", GST_OBJECT_NAME (message->src),
gst_element_state_get_name (old_state), gst_element_state_get_name (old_state),
gst_element_state_get_name (new_state)); gst_element_state_get_name (new_state));
}
if (new_state != GST_STATE_PLAYING) { if (new_state != GST_STATE_PLAYING) {
break;
hls_playing = FALSE; hls_playing = FALSE;
} break;
}
hls_playing = TRUE; hls_playing = TRUE;
GstQuery *query = NULL; GstQuery *query = NULL;
query = gst_query_new_seeking(GST_FORMAT_TIME); query = gst_query_new_seeking(GST_FORMAT_TIME);
@@ -906,6 +909,11 @@ static gboolean gstreamer_video_pipeline_bus_callback(GstBus *bus, GstMessage *m
g_printerr ("Seeking query failed."); g_printerr ("Seeking query failed.");
} }
gst_query_unref (query); gst_query_unref (query);
if (hls_requested_start_position && hls_seek_enabled) {
hls_video_seek_to_start_position(renderer_type[type]->pipeline);
}
} }
if (renderer->autovideo) { if (renderer->autovideo) {
char *sink = strstr(GST_MESSAGE_SRC_NAME(message), "-actual-sink-"); char *sink = strstr(GST_MESSAGE_SRC_NAME(message), "-actual-sink-");
@@ -1018,17 +1026,25 @@ int video_renderer_choose_codec (bool video_is_jpeg, bool video_is_h265) {
} }
return 0; return 0;
} }
bool video_get_playback_info(double *duration, double *position, float *rate, bool *buffer_empty, bool *buffer_full) { bool video_get_playback_info(double *duration, double *position, double *seek_start, double *seek_duration, float *rate, bool *buffer_empty, bool *buffer_full) {
gint64 pos = 0; gint64 pos = 0;
GstState state; GstState state;
*duration = 0.0; *duration = 0.0;
*position = -1.0; *position = -1.0;
*seek_start = 0.0;
*seek_duration = 0.0;
*rate = 0.0f; *rate = 0.0f;
if (!renderer) { if (!renderer) {
return true; return true;
} }
if (hls_seek_enabled) {
*seek_start = ((double) hls_seek_start) / GST_SECOND;
*seek_duration = ((double) (hls_seek_end - hls_seek_start)) / GST_SECOND;
}
*buffer_empty = (bool) hls_buffer_empty; *buffer_empty = (bool) hls_buffer_empty;
*buffer_full = (bool) hls_buffer_full; *buffer_full = (bool) hls_buffer_full;
gst_element_get_state(renderer->pipeline, &state, NULL, 0); gst_element_get_state(renderer->pipeline, &state, NULL, 0);

View File

@@ -68,7 +68,7 @@ unsigned int video_renderer_listen(void *loop, int id);
void video_renderer_destroy (); void video_renderer_destroy ();
void video_renderer_size(float *width_source, float *height_source, float *width, float *height); void video_renderer_size(float *width_source, float *height_source, float *width, float *height);
bool waiting_for_x11_window(); bool waiting_for_x11_window();
bool video_get_playback_info(double *duration, double *position, float *rate, bool *buffer_empty, bool *buffer_full); bool video_get_playback_info(double *duration, double *position, double *seek_start, double *seek_duration, float *rate, bool *buffer_empty, bool *buffer_full);
int video_renderer_choose_codec (bool video_is_jpeg, bool video_is_h265); 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_renderer_listen(void *loop, int id);
bool video_renderer_eos_watch(); bool video_renderer_eos_watch();

View File

@@ -2496,7 +2496,7 @@ extern "C" void on_video_play(void *cls, const char* location, const float start
url.append(location); url.append(location);
relaunch_video = true; relaunch_video = true;
preserve_connections = true; preserve_connections = true;
LOGD("********************on_video_play: location = %s***********************", url.c_str()); LOGI("********************on_video_play: location = %s*** start position %f ********************", url.c_str(), start_position);
reset_loop = true; reset_loop = true;
} }
@@ -2519,12 +2519,12 @@ extern "C" void on_video_rate(void *cls, const float rate) {
extern "C" float on_video_playlist_remove (void *cls) { extern "C" float on_video_playlist_remove (void *cls) {
double duration, position; double duration, position, seek_start, seek_end;
float rate; float rate;
bool buffer_empty, buffer_full; bool buffer_empty, buffer_full;
LOGI("************************* on_video_playlist_remove\n"); LOGI("************************* on_video_playlist_remove\n");
video_renderer_pause(); video_renderer_pause();
video_get_playback_info(&duration, &position, &rate, &buffer_empty, &buffer_full); video_get_playback_info(&duration, &position, &seek_start, &seek_end, &rate, &buffer_empty, &buffer_full);
return (float) position; return (float) position;
} }
@@ -2536,6 +2536,7 @@ extern "C" float on_video_playlist_remove (void *cls) {
extern "C" void on_video_acquire_playback_info (void *cls, playback_info_t *playback_info) { extern "C" void on_video_acquire_playback_info (void *cls, playback_info_t *playback_info) {
int buffering_level; int buffering_level;
bool still_playing = video_get_playback_info(&playback_info->duration, &playback_info->position, bool still_playing = video_get_playback_info(&playback_info->duration, &playback_info->position,
&playback_info->seek_start, &playback_info->seek_duration,
&playback_info->rate, &playback_info->rate,
&playback_info->playback_buffer_empty, &playback_info->playback_buffer_empty,
&playback_info->playback_buffer_full); &playback_info->playback_buffer_full);