如何通过GStreamer从HLS流中获取EXT-X-PROGRAM-DATE-TIME标签?
解决HLS流EXT-X-PROGRAM-DATE-TIME标签获取与绝对时间计算问题
问题根源
EXT-X-PROGRAM-DATE-TIME是HLS播放列表(m3u8)中的元数据标签,不属于GStreamer标准媒体标签体系,所以gst_discoverer_info_get_tags()无法从Discoverer信息中提取到该标签。
解决方案
方案1:直接解析HLS播放列表
既然该标签存在于m3u8文件中,可自行下载并解析播放列表内容:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> #include <glib.h> static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; char **mem = (char **)userp; *mem = realloc(*mem, strlen(*mem) + realsize + 1); if (*mem == NULL) { fprintf(stderr, "内存分配失败\n"); return 0; } strcat(*mem, contents); return realsize; } gchar* get_hls_program_datetime(const gchar* m3u8_url) { CURL *curl = curl_easy_init(); char *response = calloc(1, 1); gchar *datetime = NULL; if (curl && response) { curl_easy_setopt(curl, CURLOPT_URL, m3u8_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); CURLcode res = curl_easy_perform(curl); if (res == CURLE_OK) { char *line = strtok(response, "\n"); while (line != NULL) { if (strncmp(line, "#EXT-X-PROGRAM-DATE-TIME:", 27) == 0) { datetime = g_strdup(line + 27); g_strstrip(datetime); break; } line = strtok(NULL, "\n"); } } curl_easy_cleanup(curl); } free(response); return datetime; }
调用该函数获取时间字符串后,用g_date_time_new_from_iso8601()转成GDateTime对象,再提取Unix时间戳用于后续计算。
方案2:通过GStreamer HLS元素获取
如果使用hlssrc作为HLS源,可监听总线消息提取播放列表标签:
#include <gst/gst.h> static gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data) { if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ELEMENT) { const GstStructure *s = gst_message_get_structure(msg); if (gst_structure_has_name(s, "hls-playlist")) { GList *entries = NULL; if (gst_structure_get_list(s, "entries", &entries)) { for (GList *l = entries; l != NULL; l = l->next) { GstStructure *entry = GST_STRUCTURE(l->data); const gchar *datetime = gst_structure_get_string(entry, "EXT-X-PROGRAM-DATE-TIME"); if (datetime) { g_print("EXT-X-PROGRAM-DATE-TIME: %s\n", datetime); // 保存该时间用于后续绝对时间计算 break; } } gst_structure_list_free(entries); } } } return TRUE; } // 管道初始化时绑定总线回调 void setup_hls_bus_watch(GstPipeline *pipeline) { GstBus *bus = gst_pipeline_get_bus(pipeline); gst_bus_add_watch(bus, bus_callback, NULL); gst_object_unref(bus); }
计算当前帧绝对时间
- 将获取到的时间字符串转成Unix时间戳(单位:秒):
GDateTime *start_time = g_date_time_new_from_iso8601(datetime_str, NULL); gint64 start_timestamp = g_date_time_to_unix(start_time); g_date_time_unref(start_time);
- 把当前帧的PTS(纳秒单位)转成秒,加到启动时间戳上得到绝对时间:
// frame_pts为当前帧的PTS,类型为GstClockTime gdouble pts_seconds = GST_TIME_AS_SECONDS(frame_pts); gint64 absolute_timestamp = start_timestamp + (gint64)pts_seconds;
内容的提问来源于stack exchange,提问作者Il'ya Zhenin
相关产品推荐
相关产品推荐

