int imkh_cctv;
#if CONFIG_VOBSUB_DEMUXER
AVFormatContext *sub_ctx;
- FFDemuxSubtitlesQueue q;
+ FFDemuxSubtitlesQueue q[32];
#endif
} MpegDemuxContext;
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);
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', "
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;
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);
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;
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)
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;
return 0;
fail:
+ av_free_packet(pkt);
av_free_packet(&idx_pkt);
return ret;
}
* 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,
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;
return sub;
}
-static int cmp_pkt_sub(const void *a, const void *b)
+static int cmp_pkt_sub_ts_pos(const void *a, const void *b)
{
const AVPacket *s1 = a;
const AVPacket *s2 = b;
return s1->pts > s2->pts ? 1 : -1;
}
+static int cmp_pkt_sub_pos_ts(const void *a, const void *b)
+{
+ const AVPacket *s1 = a;
+ const AVPacket *s2 = b;
+ if (s1->pos == s2->pos) {
+ if (s1->pts == s2->pts)
+ return 0;
+ return s1->pts > s2->pts ? 1 : -1;
+ }
+ return s1->pos > s2->pos ? 1 : -1;
+}
+
void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q)
{
int i;
- qsort(q->subs, q->nb_subs, sizeof(*q->subs), cmp_pkt_sub);
+ qsort(q->subs, q->nb_subs, sizeof(*q->subs),
+ q->sort == SUB_SORT_TS_POS ? cmp_pkt_sub_ts_pos
+ : cmp_pkt_sub_pos_ts);
for (i = 0; i < q->nb_subs; i++)
if (q->subs[i].duration == -1 && i < q->nb_subs - 1)
q->subs[i].duration = q->subs[i + 1].pts - q->subs[i].pts;
1, 15355, 15355, 4733, 2094, 0x3c171425, F=0x0
1, 48797, 48797, 2560, 2480, 0x7c0edf21, F=0x0
1, 51433, 51433, 2366, 3059, 0xc95b8a05, F=0x0
-1, 53919, 53919, 2696, 2095, 0x61bb15ed, F=0x0
+1, 53910, 53910, 2696, 2095, 0x61bb15ed, F=0x0
1, 56663, 56663, 1262, 1013, 0xc9ae89b7, F=0x0
1, 58014, 58014, 1661, 969, 0xe01878f0, F=0x0
1, 67724, 67724, 1365, 844, 0xe7db4fc1, F=0x0
1, 191356, 191356, 1228, 1517, 0xae8c5c2b, F=0x0
1, 192640, 192640, 1763, 2506, 0xa458d6d4, F=0x0
1, 195193, 195193, 1092, 1074, 0x397ba9a8, F=0x0
-1, 196369, 196369, 1524, 1715, 0x695ca41e, F=0x0
+1, 196361, 196361, 1524, 1715, 0x695ca41e, F=0x0
1, 197946, 197946, 1160, 789, 0xc63a189e, F=0x0
1, 199230, 199230, 1627, 1846, 0xeea8c599, F=0x0
1, 200924, 200924, 1763, 922, 0xd4a87222, F=0x0
1, 210600, 210600, 1831, 665, 0x55580135, F=0x0
1, 214771, 214771, 1558, 1216, 0x50d1f6c5, F=0x0
1, 225640, 225640, 2127, 2133, 0x670c11a5, F=0x0
-1, 227834, 227834, 1262, 1264, 0xc1d9fc57, F=0x0