You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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);
}

计算当前帧绝对时间

  1. 将获取到的时间字符串转成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);
  1. 把当前帧的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 14:53:39