Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fftools/ffmpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -2117,6 +2117,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
} else
opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->mux_timebase);
opkt.dts -= ost_tb_start_time;
opkt.gts = pkt->gts;

opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->mux_timebase);

Expand Down
2 changes: 2 additions & 0 deletions libavcodec/avpacket.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ void av_init_packet(AVPacket *pkt)
pkt->pts = AV_NOPTS_VALUE;
pkt->dts = AV_NOPTS_VALUE;
pkt->pos = -1;
pkt->gts = -1;
pkt->duration = 0;
#if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGS
Expand Down Expand Up @@ -575,6 +576,7 @@ int av_packet_copy_props(AVPacket *dst, const AVPacket *src)

dst->pts = src->pts;
dst->dts = src->dts;
dst->gts = src->gts;
dst->pos = src->pos;
dst->duration = src->duration;
#if FF_API_CONVERGENCE_DURATION
Expand Down
1 change: 1 addition & 0 deletions libavcodec/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
frame->pkt_pos = pkt->pos;
frame->pkt_duration = pkt->duration;
frame->pkt_size = pkt->size;
frame->gts = pkt->gts;

for (i = 0; i < FF_ARRAY_ELEMS(sd); i++) {
int size;
Expand Down
9 changes: 9 additions & 0 deletions libavcodec/encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt)
AVFrame *frame = es->in_frame;
int got_packet;
int ret;
double gts = -1;

if (avci->draining_done)
return AVERROR_EOF;
Expand All @@ -137,6 +138,10 @@ static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt)
return ret;
}

// record frame global timestamp
if (frame)
gts = frame->gts;

if (!frame->buf[0]) {
if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY ||
(avci->frame_thread_encoder && avctx->active_thread_type & FF_THREAD_FRAME)))
Expand Down Expand Up @@ -164,6 +169,10 @@ static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt)
avpkt->pts = avpkt->dts = frame->pts;
}

// assign global timestamp if available
if (gts > 0 && avpkt->gts <= 0)
avpkt->gts = gts;

av_assert0(ret <= 0);

emms_c();
Expand Down
2 changes: 2 additions & 0 deletions libavcodec/packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,8 @@ typedef struct AVPacket {
attribute_deprecated
int64_t convergence_duration;
#endif

double gts;
} AVPacket;

typedef struct AVPacketList {
Expand Down
5 changes: 4 additions & 1 deletion libavformat/avformat.h
Original file line number Diff line number Diff line change
Expand Up @@ -2810,8 +2810,11 @@ void av_dump_format(AVFormatContext *ic,
* @param flags AV_FRAME_FILENAME_FLAGS_*
* @return 0 if OK, -1 on format error
*/
int av_get_frame_filename3(char *buf, int buf_size,
const char *path, int number, int flags, int64_t ts, double duration, double global_timestamp);

int av_get_frame_filename2(char *buf, int buf_size,
const char *path, int number, int flags);
const char *path, int number, int flags, int64_t ts);

int av_get_frame_filename(char *buf, int buf_size,
const char *path, int number);
Expand Down
56 changes: 56 additions & 0 deletions libavformat/hls.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/time.h"
#include "libavutil/time_internal.h"
#include "avformat.h"
#include "internal.h"
#include "avio_internal.h"
Expand Down Expand Up @@ -75,6 +76,8 @@ struct segment {
uint8_t iv[16];
/* associated Media Initialization Section, treated as a segment */
struct segment *init_section;
double program_date_time;
int64_t initial_dts;
};

struct rendition;
Expand Down Expand Up @@ -723,6 +726,7 @@ static int parse_playlist(HLSContext *c, const char *url,
struct segment **prev_segments = NULL;
int prev_n_segments = 0;
int64_t prev_start_seq_no = -1;
double program_date_time = -1;

if (is_http && !in && c->http_persistent && c->playlist_pb) {
in = c->playlist_pb;
Expand Down Expand Up @@ -872,6 +876,28 @@ static int parse_playlist(HLSContext *c, const char *url,
ptr = strchr(ptr, '@');
if (ptr)
seg_offset = strtoll(ptr+1, NULL, 10);
} else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) {
struct tm pdt;
int y,M,d,h,m;
double s;

// TODO: take timezone into consideration
if (sscanf(ptr, "%d-%d-%dT%d:%d:%lf", &y, &M, &d, &h, &m, &s) != 6) {
ret = AVERROR_INVALIDDATA;
goto fail;
}

pdt.tm_year = y - 1900;
pdt.tm_mon = M - 1;
pdt.tm_mday = d;
pdt.tm_hour = h;
pdt.tm_min = m;
pdt.tm_sec = 0;
pdt.tm_isdst = -1;

program_date_time = ff_timegm(&pdt);
program_date_time += s;
// TODO: avoid rounding errors by tracking ms separately
} else if (av_strstart(line, "#", NULL)) {
av_log(c->ctx, AV_LOG_INFO, "Skip ('%s')\n", line);
continue;
Expand Down Expand Up @@ -941,6 +967,13 @@ static int parse_playlist(HLSContext *c, const char *url,
}
seg->duration = duration;
seg->key_type = key_type;

seg->program_date_time = program_date_time;
if (program_date_time > 0) {
program_date_time += (double) duration / AV_TIME_BASE;
}
seg->initial_dts = -1;

dynarray_add(&pls->segments, &pls->n_segments, seg);
is_segment = 0;

Expand Down Expand Up @@ -992,8 +1025,20 @@ static int parse_playlist(HLSContext *c, const char *url,
return ret;
}

static struct segment *closest_segment(struct playlist *pls) {
int n = pls->cur_seq_no - pls->start_seq_no;
if (n < 0)
return pls->segments[0];
if (n >= pls->n_segments)
return pls->segments[pls->n_segments - 1];
return pls->segments[pls->cur_seq_no - pls->start_seq_no];
}

static struct segment *current_segment(struct playlist *pls)
{
int n = pls->cur_seq_no - pls->start_seq_no;
if (n >= pls->n_segments)
return NULL;
return pls->segments[pls->cur_seq_no - pls->start_seq_no];
}

Expand Down Expand Up @@ -2163,6 +2208,17 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt)
return ret;
break;
} else {
struct segment *seg = closest_segment(pls);
if (seg->initial_dts < 0 && pls->pkt.dts != AV_NOPTS_VALUE) {
seg->initial_dts = pls->pkt.dts;
}

if (pls->pkt.pts != AV_NOPTS_VALUE && seg->program_date_time > 0 && seg->initial_dts > 0) {
pls->pkt.gts = seg->program_date_time + (pls->pkt.pts - seg->initial_dts) * av_q2d(get_timebase(pls));
} else {
pls->pkt.gts = -1;
}

/* stream_index check prevents matching picture attachments etc. */
if (pls->is_id3_timestamped && pls->pkt.stream_index == 0) {
/* audio elementary streams are id3 timestamped */
Expand Down
15 changes: 9 additions & 6 deletions libavformat/hlsenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1265,9 +1265,11 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
}
} else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) {
struct tm program_date_time;
int y,M,d,h,m,s;
double ms;
if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) {
int y,M,d,h,m;
double s;

// TODO: take timezone into consideration
if (sscanf(ptr, "%d-%d-%dT%d:%d:%lf", &y, &M, &d, &h, &m, &s) != 6) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
Expand All @@ -1277,11 +1279,12 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
program_date_time.tm_mday = d;
program_date_time.tm_hour = h;
program_date_time.tm_min = m;
program_date_time.tm_sec = s;
program_date_time.tm_sec = 0;
program_date_time.tm_isdst = -1;

discont_program_date_time = mktime(&program_date_time);
discont_program_date_time += (double)(ms / 1000);
discont_program_date_time = ff_timegm(&program_date_time);
discont_program_date_time += s;
// TODO: avoid rounding errors by tracking ms separately
} else if (av_strstart(line, "#", NULL)) {
continue;
} else if (line[0]) {
Expand Down
49 changes: 38 additions & 11 deletions libavformat/img2enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/time.h"
#include "libavutil/time_internal.h"
#include <sys/time.h>
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
Expand All @@ -42,6 +44,7 @@ typedef struct VideoMuxData {
char target[4][1024];
int update;
int use_strftime;
int use_global_timestamp;
int frame_pts;
const char *muxer;
int use_rename;
Expand Down Expand Up @@ -130,31 +133,54 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
VideoMuxData *img = s->priv_data;
AVIOContext *pb[4] = {0};
char filename[1024];
AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
AVStream *stream = s->streams[pkt->stream_index];
AVCodecParameters *par = stream->codecpar;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(par->format);
int ret, i;
int nb_renames = 0;
int64_t ts = av_rescale_q(pkt->pts, stream->time_base, AV_TIME_BASE_Q);
AVDictionary *options = NULL;

if (img->update) {
av_strlcpy(filename, img->path, sizeof(filename));
} else if (img->use_strftime) {
time_t now0;
struct tm *tm, tmpbuf;
time(&now0);
tm = localtime_r(&now0, &tmpbuf);
if (!strftime(filename, sizeof(filename), img->path, tm)) {
av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n");
return AVERROR(EINVAL);
} else if (img->use_strftime || img->frame_pts || img->use_global_timestamp) {
char temp_name[sizeof(filename)];
if (img->use_strftime) {
struct timeval tv;
gettimeofday(&tv, NULL);
if (!av_strftime_micro(temp_name, sizeof(temp_name), img->path, &tv)) {
av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n");
return AVERROR(EINVAL);
}
} else {
av_strlcpy(temp_name, img->path, sizeof(temp_name));
}

if (img->frame_pts || img->use_global_timestamp) {
double global_timestamp = pkt->gts;
if (av_get_frame_filename3(filename, sizeof(filename), temp_name, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE, ts, 0, global_timestamp) < 0) {
av_log(s, AV_LOG_ERROR, "Cannot write filename by pts of the frames.");
return AVERROR(EINVAL);
}
} else {
av_strlcpy(filename, temp_name, sizeof(filename));
}
} else if (av_get_frame_filename2(filename, sizeof(filename), img->path,
img->img_number,
AV_FRAME_FILENAME_FLAGS_MULTIPLE, ts) < 0 &&
img->img_number > 1) {
av_log(s, AV_LOG_ERROR,
"Could not get frame filename number %d from pattern '%s' (either set update or use a pattern like %%03d within the filename pattern)\n",
img->img_number, img->path);
return AVERROR(EINVAL);
} else if (img->frame_pts) {
if (av_get_frame_filename2(filename, sizeof(filename), img->path, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
if (av_get_frame_filename2(filename, sizeof(filename), img->path, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE, ts) < 0) {
av_log(s, AV_LOG_ERROR, "Cannot write filename by pts of the frames.");
return AVERROR(EINVAL);
}
} else if (av_get_frame_filename2(filename, sizeof(filename), img->path,
img->img_number,
AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0 &&
AV_FRAME_FILENAME_FLAGS_MULTIPLE, ts) < 0 &&
img->img_number > 1) {
av_log(s, AV_LOG_ERROR,
"Could not get frame filename number %d from pattern '%s'. "
Expand Down Expand Up @@ -244,6 +270,7 @@ static const AVOption muxoptions[] = {
{ "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC },
{ "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
{ "frame_pts", "use current frame pts for filename", OFFSET(frame_pts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
{ "global_timestamp", "use global timestamp for filename", OFFSET(use_global_timestamp), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
{ "atomic_writing", "write files atomically (using temporary files and renames)", OFFSET(use_rename), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
{ "protocol_opts", "specify protocol options for the opened files", OFFSET(protocol_opts), AV_OPT_TYPE_DICT, {0}, 0, 0, ENC },
{ NULL },
Expand Down
Loading