|
|
|
@ -27,24 +27,16 @@ |
|
|
|
|
|
|
|
|
|
#include "avformat.h" |
|
|
|
|
#include "internal.h" |
|
|
|
|
#include "subtitles.h" |
|
|
|
|
#include "libavcodec/jacosub.h" |
|
|
|
|
#include "libavutil/avstring.h" |
|
|
|
|
#include "libavutil/bprint.h" |
|
|
|
|
#include "libavutil/intreadwrite.h" |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
char *line; ///< null-terminated heap allocated subtitle line
|
|
|
|
|
int64_t pos; ///< offset position
|
|
|
|
|
int start; ///< timestamp start
|
|
|
|
|
int end; ///< timestamp end
|
|
|
|
|
} SubEntry; |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
int shift; |
|
|
|
|
unsigned timeres; |
|
|
|
|
SubEntry *subs; ///< subtitles list
|
|
|
|
|
int nsub; ///< number of subtitles
|
|
|
|
|
int sid; ///< current subtitle
|
|
|
|
|
FFDemuxSubtitlesQueue q; |
|
|
|
|
} JACOsubContext; |
|
|
|
|
|
|
|
|
|
static int timed_line(const char *ptr) |
|
|
|
@ -101,41 +93,39 @@ static int get_jss_cmd(char k) |
|
|
|
|
|
|
|
|
|
static int jacosub_read_close(AVFormatContext *s) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
|
JACOsubContext *jacosub = s->priv_data; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < jacosub->nsub; i++) |
|
|
|
|
av_freep(&jacosub->subs[i].line); |
|
|
|
|
jacosub->nsub = 0; |
|
|
|
|
av_freep(&jacosub->subs); |
|
|
|
|
ff_subtitles_queue_clean(&jacosub->q); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const char *read_ts(JACOsubContext *jacosub, const char *buf, |
|
|
|
|
int *ts_start, int *ts_end) |
|
|
|
|
int64_t *start, int *duration) |
|
|
|
|
{ |
|
|
|
|
int len; |
|
|
|
|
unsigned hs, ms, ss, fs; // hours, minutes, seconds, frame start
|
|
|
|
|
unsigned he, me, se, fe; // hours, minutes, seconds, frame end
|
|
|
|
|
int ts_start, ts_end; |
|
|
|
|
|
|
|
|
|
/* timed format */ |
|
|
|
|
if (sscanf(buf, "%u:%u:%u.%u %u:%u:%u.%u %n", |
|
|
|
|
&hs, &ms, &ss, &fs, |
|
|
|
|
&he, &me, &se, &fe, &len) == 8) { |
|
|
|
|
*ts_start = (hs*3600 + ms*60 + ss) * jacosub->timeres + fs; |
|
|
|
|
*ts_end = (he*3600 + me*60 + se) * jacosub->timeres + fe; |
|
|
|
|
ts_start = (hs*3600 + ms*60 + ss) * jacosub->timeres + fs; |
|
|
|
|
ts_end = (he*3600 + me*60 + se) * jacosub->timeres + fe; |
|
|
|
|
goto shift_and_ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* timestamps format */ |
|
|
|
|
if (sscanf(buf, "@%u @%u %n", ts_start, ts_end, &len) == 2) |
|
|
|
|
if (sscanf(buf, "@%u @%u %n", &ts_start, &ts_end, &len) == 2) |
|
|
|
|
goto shift_and_ret; |
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
shift_and_ret: |
|
|
|
|
*ts_start = (*ts_start + jacosub->shift) * 100 / jacosub->timeres; |
|
|
|
|
*ts_end = (*ts_end + jacosub->shift) * 100 / jacosub->timeres; |
|
|
|
|
ts_start = (ts_start + jacosub->shift) * 100 / jacosub->timeres; |
|
|
|
|
ts_end = (ts_end + jacosub->shift) * 100 / jacosub->timeres; |
|
|
|
|
*start = ts_start; |
|
|
|
|
*duration = ts_start + ts_end; |
|
|
|
|
return buf + len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -161,11 +151,6 @@ static int get_shift(int timeres, const char *buf) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int cmp_timed_sub(const void *a, const void *b) |
|
|
|
|
{ |
|
|
|
|
return ((const SubEntry*)a)->start - ((const SubEntry*)b)->start; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int jacosub_read_header(AVFormatContext *s) |
|
|
|
|
{ |
|
|
|
|
AVBPrint header; |
|
|
|
@ -191,41 +176,19 @@ static int jacosub_read_header(AVFormatContext *s) |
|
|
|
|
int cmd_len; |
|
|
|
|
const char *p = line; |
|
|
|
|
int64_t pos = avio_tell(pb); |
|
|
|
|
|
|
|
|
|
ff_get_line(pb, line, sizeof(line)); |
|
|
|
|
int len = ff_get_line(pb, line, sizeof(line)); |
|
|
|
|
|
|
|
|
|
p = jss_skip_whitespace(p); |
|
|
|
|
|
|
|
|
|
/* queue timed line */ |
|
|
|
|
if (merge_line || timed_line(p)) { |
|
|
|
|
SubEntry *subs, *sub; |
|
|
|
|
const int len = strlen(line); |
|
|
|
|
|
|
|
|
|
if (merge_line) { |
|
|
|
|
char *tmp; |
|
|
|
|
const int old_len = strlen(sub->line); |
|
|
|
|
|
|
|
|
|
sub = &subs[jacosub->nsub]; |
|
|
|
|
tmp = av_realloc(sub->line, old_len + len + 1); |
|
|
|
|
if (!tmp) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
sub->line = tmp; |
|
|
|
|
strcpy(sub->line + old_len, line); |
|
|
|
|
} else { |
|
|
|
|
subs = av_realloc(jacosub->subs, |
|
|
|
|
sizeof(*jacosub->subs) * (jacosub->nsub+1)); |
|
|
|
|
if (!subs) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
jacosub->subs = subs; |
|
|
|
|
sub = &subs[jacosub->nsub]; |
|
|
|
|
sub->pos = pos; |
|
|
|
|
sub->line = av_strdup(line); |
|
|
|
|
if (!sub->line) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
} |
|
|
|
|
AVPacket *sub; |
|
|
|
|
|
|
|
|
|
sub = ff_subtitles_queue_insert(&jacosub->q, line, len, merge_line); |
|
|
|
|
if (!sub) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
sub->pos = pos; |
|
|
|
|
merge_line = len > 1 && !strcmp(&line[len - 2], "\\\n"); |
|
|
|
|
if (!merge_line) |
|
|
|
|
jacosub->nsub++; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -267,32 +230,19 @@ static int jacosub_read_header(AVFormatContext *s) |
|
|
|
|
|
|
|
|
|
/* SHIFT and TIMERES affect the whole script so packet timing can only be
|
|
|
|
|
* done in a second pass */ |
|
|
|
|
for (i = 0; i < jacosub->nsub; i++) { |
|
|
|
|
SubEntry *sub = &jacosub->subs[i]; |
|
|
|
|
read_ts(jacosub, sub->line, &sub->start, &sub->end); |
|
|
|
|
for (i = 0; i < jacosub->q.nb_subs; i++) { |
|
|
|
|
AVPacket *sub = &jacosub->q.subs[i]; |
|
|
|
|
read_ts(jacosub, sub->data, &sub->pts, &sub->duration); |
|
|
|
|
} |
|
|
|
|
qsort(jacosub->subs, jacosub->nsub, sizeof(*jacosub->subs), cmp_timed_sub); |
|
|
|
|
ff_subtitles_queue_finalize(&jacosub->q); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int jacosub_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
{ |
|
|
|
|
int res; |
|
|
|
|
JACOsubContext *jacosub = s->priv_data; |
|
|
|
|
const SubEntry *sub = &jacosub->subs[jacosub->sid++]; |
|
|
|
|
|
|
|
|
|
if (jacosub->sid == jacosub->nsub) |
|
|
|
|
return AVERROR_EOF; |
|
|
|
|
res = av_new_packet(pkt, strlen(sub->line)); |
|
|
|
|
if (res) |
|
|
|
|
return res; |
|
|
|
|
strcpy(pkt->data, sub->line); |
|
|
|
|
pkt->flags |= AV_PKT_FLAG_KEY; |
|
|
|
|
pkt->pos = sub->pos; |
|
|
|
|
pkt->pts = pkt->dts = sub->start; |
|
|
|
|
pkt->duration = sub->end - sub->start; |
|
|
|
|
return 0; |
|
|
|
|
return ff_subtitles_queue_read_packet(&jacosub->q, pkt); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
AVInputFormat ff_jacosub_demuxer = { |
|
|
|
|