Home/News | About | Download | Documentation | Forum | Bug Reports | Contact | Donations | Consulting | Projects | Legal | Security | FATE


This forum has not been maintained for a long time and will probably get deleted in the near future.
For faster responses to your questions, please use StackOverflow instead and tag your questions with "FFmpeg".
If you need a backup of the posts from this forum, please contact me directly.

added #EXT-X-PROGRAM-DATE-TIME: to m3u8

Suggestions and feature requests, whislists, etc.

added #EXT-X-PROGRAM-DATE-TIME: to m3u8

Postby mrcrab » Wed Apr 06, 2016 12:21 pm

We needed the EXT-X-PROGRAM-DATE-TIME timestamp of the first .ts segment to be included in the m3u8 manifest, so we added something to help. Not sure how or if we should submit this change to ffmpeg, so we're submitting it here for comment. Please note, that this change actually sets the timestamp at the last .ts, not the first, but that's because we didn't really know how to do it correctly. This works for our purpose, maybe it will suffice for someone else who needs something like this.

HLSENC.C
Code: Select all
#include "libavutil/time_internal.h"

/* BEGIN INSERT PROGRAM-DATE-TIME */
#include "libavutil/time.h"
/* END INSERT PROGRAM-DATE-TIME */

#include "avformat.h"

...

   char *key_uri = NULL;
    char *iv_string = NULL;

/* BEGIN INSERT PROGRAM-DATE-TIME */
    time_t current_time;
    char* c_time_string;
    current_time = time(NULL);
    c_time_string = ctime(&current_time);
/* END INSERT PROGRAM-DATE-TIME */

    if (!use_rename && !warned_non_file++)
        av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporarly partial files\n");

    snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename);
    if ((ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE,
                          &s->interrupt_callback, NULL)) < 0)
        goto fail;

    for (en = hls->segments; en; en = en->next) {
        if (target_duration < en->duration)
            target_duration = ceil(en->duration);
    }

    hls->discontinuity_set = 0;
    avio_printf(out, "#EXTM3U\n");
    avio_printf(out, "#EXT-X-VERSION:%d\n", version);
    if (hls->allowcache == 0 || hls->allowcache == 1) {
        avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
    }
    avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration);

/* BEGIN INSERT PROGRAM-DATE-TIME */
    avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s", c_time_string);
/* END INSERT PROGRAM-DATE-TIME */

    avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);

    av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n",
           sequence);
    if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && hls->discontinuity_set==0 ){
        avio_printf(out, "#EXT-X-DISCONTINUITY\n");
        hls->discontinuity_set = 1;
    }

......

    if( hls->vtt_m3u8_name ) {
        if ((ret = avio_open2(&sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE,
                          &s->interrupt_callback, NULL)) < 0)
            goto fail;
        avio_printf(sub_out, "#EXTM3U\n");
        avio_printf(sub_out, "#EXT-X-VERSION:%d\n", version);
        if (hls->allowcache == 0 || hls->allowcache == 1) {
            avio_printf(sub_out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
        }
        avio_printf(sub_out, "#EXT-X-TARGETDURATION:%d\n", target_duration);

/* BEGIN INSERT PROGRAM-DATE-TIME */
    avio_printf(sub_out, "#EXT-X-PROGRAM-DATE-TIME:%s", c_time_string);
/* END INSERT PROGRAM-DATE-TIME */

        avio_printf(sub_out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);




SEGMENT.C

Code: Select all
#include "libavutil/time_internal.h"
#include "libavutil/timestamp.h"


static int segment_list_open(AVFormatContext *s)
{
    SegmentContext *seg = s->priv_data;
    int ret;

/* BEGIN INSERT PROGRAM-DATE-TIME */
    time_t current_time;
    char* c_time_string;
    current_time = time(NULL);
    c_time_string = ctime(&current_time);
/* END INSERT PROGRAM-DATE-TIME */


    snprintf(seg->temp_list_filename, sizeof(seg->temp_list_filename), seg->use_rename ? "%s.tmp" : "%s", seg->list);
    ret = avio_open2(&seg->list_pb, seg->temp_list_filename, AVIO_FLAG_WRITE,
                     &s->interrupt_callback, NULL);
    if (ret < 0) {
        av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list);
        return ret;
    }

    if (seg->list_type == LIST_TYPE_M3U8 && seg->segment_list_entries) {
        SegmentListEntry *entry;
        double max_duration = 0;

        avio_printf(seg->list_pb, "#EXTM3U\n");
        avio_printf(seg->list_pb, "#EXT-X-VERSION:3\n");
        avio_printf(seg->list_pb, "#EXT-X-MEDIA-SEQUENCE:%d\n", seg->segment_list_entries->index);
        avio_printf(seg->list_pb, "#EXT-X-ALLOW-CACHE:%s\n",
                    seg->list_flags & SEGMENT_LIST_FLAG_CACHE ? "YES" : "NO");

        av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%d\n",
               seg->segment_list_entries->index);

        for (entry = seg->segment_list_entries; entry; entry = entry->next)
            max_duration = FFMAX(max_duration, entry->end_time - entry->start_time);
        avio_printf(seg->list_pb, "#EXT-X-TARGETDURATION:%"PRId64"\n", (int64_t)ceil(max_duration));

/* BEGIN INSERT PROGRAM-DATE-TIME */
    avio_printf(seg->list_pb, "#EXT-X-PROGRAM-DATE-TIME:%s", c_time_string);
/* END INSERT PROGRAM-DATE-TIME */

    } else if (seg->list_type == LIST_TYPE_FFCONCAT) {
        avio_printf(seg->list_pb, "ffconcat version 1.0\n");
    }

    return ret;
}

mrcrab
 
Posts: 1
Joined: Wed Apr 06, 2016 12:06 pm

Return to Suggestions

Who is online

Users browsing this forum: No registered users and 1 guest

cron