|
|
@@ -113,7 +113,7 @@ typedef struct MpegDemuxContext { |
|
|
|
int imkh_cctv; |
|
|
|
#if CONFIG_VOBSUB_DEMUXER |
|
|
|
AVFormatContext *sub_ctx; |
|
|
|
FFDemuxSubtitlesQueue q; |
|
|
|
FFDemuxSubtitlesQueue q[32]; |
|
|
|
#endif |
|
|
|
} MpegDemuxContext; |
|
|
|
|
|
|
@@ -693,6 +693,12 @@ static int vobsub_read_header(AVFormatContext *s) |
|
|
|
stream_id = 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (stream_id >= FF_ARRAY_ELEMS(vobsub->q)) { |
|
|
|
av_log(s, AV_LOG_ERROR, "Maximum number of subtitles streams reached\n"); |
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
goto end; |
|
|
|
} |
|
|
|
|
|
|
|
st = avformat_new_stream(s, NULL); |
|
|
|
if (!st) { |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
@@ -712,6 +718,12 @@ static int vobsub_read_header(AVFormatContext *s) |
|
|
|
int64_t pos, timestamp; |
|
|
|
const char *p = line + 10; |
|
|
|
|
|
|
|
if (!s->nb_streams) { |
|
|
|
av_log(s, AV_LOG_ERROR, "Timestamp declared before any stream\n"); |
|
|
|
ret = AVERROR_INVALIDDATA; |
|
|
|
goto end; |
|
|
|
} |
|
|
|
|
|
|
|
if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"SCNx64, |
|
|
|
&hh, &mm, &ss, &ms, &pos) != 5) { |
|
|
|
av_log(s, AV_LOG_ERROR, "Unable to parse timestamp line '%s', " |
|
|
@@ -721,7 +733,7 @@ static int vobsub_read_header(AVFormatContext *s) |
|
|
|
timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay; |
|
|
|
timestamp = av_rescale_q(timestamp, (AVRational){1,1000}, st->time_base); |
|
|
|
|
|
|
|
sub = ff_subtitles_queue_insert(&vobsub->q, "", 0, 0); |
|
|
|
sub = ff_subtitles_queue_insert(&vobsub->q[s->nb_streams - 1], "", 0, 0); |
|
|
|
if (!sub) { |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
|
goto end; |
|
|
@@ -767,7 +779,10 @@ static int vobsub_read_header(AVFormatContext *s) |
|
|
|
if (langidx < s->nb_streams) |
|
|
|
s->streams[langidx]->disposition |= AV_DISPOSITION_DEFAULT; |
|
|
|
|
|
|
|
ff_subtitles_queue_finalize(&vobsub->q); |
|
|
|
for (i = 0; i < s->nb_streams; i++) { |
|
|
|
vobsub->q[i].sort = SUB_SORT_POS_TS; |
|
|
|
ff_subtitles_queue_finalize(&vobsub->q[i]); |
|
|
|
} |
|
|
|
|
|
|
|
if (!av_bprint_is_complete(&header)) { |
|
|
|
av_bprint_finalize(&header, NULL); |
|
|
@@ -792,11 +807,22 @@ end: |
|
|
|
static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
{ |
|
|
|
MpegDemuxContext *vobsub = s->priv_data; |
|
|
|
FFDemuxSubtitlesQueue *q = &vobsub->q; |
|
|
|
FFDemuxSubtitlesQueue *q; |
|
|
|
AVIOContext *pb = vobsub->sub_ctx->pb; |
|
|
|
int ret, psize, len16 = -1; |
|
|
|
int ret, psize, total_read = 0, i; |
|
|
|
AVPacket idx_pkt; |
|
|
|
|
|
|
|
int64_t min_ts = INT64_MAX; |
|
|
|
int sid = 0; |
|
|
|
for (i = 0; i < s->nb_streams; i++) { |
|
|
|
FFDemuxSubtitlesQueue *tmpq = &vobsub->q[i]; |
|
|
|
int64_t ts = tmpq->subs[tmpq->current_sub_idx].pts; |
|
|
|
if (ts < min_ts) { |
|
|
|
min_ts = ts; |
|
|
|
sid = i; |
|
|
|
} |
|
|
|
} |
|
|
|
q = &vobsub->q[sid]; |
|
|
|
ret = ff_subtitles_queue_read_packet(q, &idx_pkt); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
@@ -819,19 +845,20 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
do { |
|
|
|
int n, to_read, startcode; |
|
|
|
int64_t pts, dts; |
|
|
|
int64_t old_pos = avio_tell(pb), new_pos; |
|
|
|
int pkt_size; |
|
|
|
|
|
|
|
ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts); |
|
|
|
if (ret < 0) |
|
|
|
FAIL(ret); |
|
|
|
to_read = ret & 0xffff; |
|
|
|
new_pos = avio_tell(pb); |
|
|
|
pkt_size = ret + (new_pos - old_pos); |
|
|
|
|
|
|
|
/* this prevents reads above the current packet */ |
|
|
|
if (pkt->size + to_read > psize) |
|
|
|
break; |
|
|
|
|
|
|
|
/* if the len is computed, we check for overread */ |
|
|
|
if (len16 != -1 && pkt->size + to_read > len16) |
|
|
|
if (total_read + pkt_size > psize) |
|
|
|
break; |
|
|
|
total_read += pkt_size; |
|
|
|
|
|
|
|
/* the current chunk doesn't match the stream index (unlikely) */ |
|
|
|
if ((startcode & 0x1f) != idx_pkt.stream_index) |
|
|
@@ -844,11 +871,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read); |
|
|
|
if (n < to_read) |
|
|
|
pkt->size -= to_read - n; |
|
|
|
|
|
|
|
/* first chunk contains the total len of the packet to raise */ |
|
|
|
if (len16 == -1 && n > 2) |
|
|
|
len16 = AV_RB16(pkt->data); |
|
|
|
} while (len16 != -1 && pkt->size != len16); |
|
|
|
} while (total_read < psize); |
|
|
|
|
|
|
|
pkt->pts = pkt->dts = idx_pkt.pts; |
|
|
|
pkt->pos = idx_pkt.pos; |
|
|
@@ -858,6 +881,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
return 0; |
|
|
|
|
|
|
|
fail: |
|
|
|
av_free_packet(pkt); |
|
|
|
av_free_packet(&idx_pkt); |
|
|
|
return ret; |
|
|
|
} |
|
|
@@ -871,6 +895,7 @@ static int vobsub_read_seek(AVFormatContext *s, int stream_index, |
|
|
|
* same for all subtitles stream within a .idx/.sub). Rescaling is done just |
|
|
|
* like in avformat_seek_file(). */ |
|
|
|
if (stream_index == -1 && s->nb_streams != 1) { |
|
|
|
int i, ret = 0; |
|
|
|
AVRational time_base = s->streams[0]->time_base; |
|
|
|
ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); |
|
|
|
min_ts = av_rescale_rnd(min_ts, time_base.den, |
|
|
@@ -879,16 +904,26 @@ static int vobsub_read_seek(AVFormatContext *s, int stream_index, |
|
|
|
max_ts = av_rescale_rnd(max_ts, time_base.den, |
|
|
|
time_base.num * (int64_t)AV_TIME_BASE, |
|
|
|
AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); |
|
|
|
for (i = 0; i < s->nb_streams; i++) { |
|
|
|
int r = ff_subtitles_queue_seek(&vobsub->q[i], s, stream_index, |
|
|
|
min_ts, ts, max_ts, flags); |
|
|
|
if (r < 0) |
|
|
|
ret = r; |
|
|
|
} |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
return ff_subtitles_queue_seek(&vobsub->q, s, stream_index, |
|
|
|
return ff_subtitles_queue_seek(&vobsub->q[stream_index], s, stream_index, |
|
|
|
min_ts, ts, max_ts, flags); |
|
|
|
} |
|
|
|
|
|
|
|
static int vobsub_read_close(AVFormatContext *s) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
MpegDemuxContext *vobsub = s->priv_data; |
|
|
|
ff_subtitles_queue_clean(&vobsub->q); |
|
|
|
|
|
|
|
for (i = 0; i < s->nb_streams; i++) |
|
|
|
ff_subtitles_queue_clean(&vobsub->q[i]); |
|
|
|
if (vobsub->sub_ctx) |
|
|
|
avformat_close_input(&vobsub->sub_ctx); |
|
|
|
return 0; |
|
|
|