diff options
author | Clément Bœsch <ubitux@gmail.com> | 2012-05-27 00:37:02 +0400 |
---|---|---|
committer | Clément Bœsch <ubitux@gmail.com> | 2012-05-29 23:33:28 +0400 |
commit | 2d52ee8a1a4f9438df90f3c95a6fbfc8f6e812f3 (patch) | |
tree | 13f4a32e21cffcaa53526d5f5f5dc420028d3aeb /libavformat/microdvddec.c | |
parent | d51e08bb89f7a93f471bc14ad00c14ac986cfcf0 (diff) |
lavf/microdvd: support events lasting to the next one.
Example:
{3350}{}this subtitle...
{3390}{}...continues up to...
{4000}{4500}this one.
{4600}{}and now...
{4800}{}...to the end of the presentation
Diffstat (limited to 'libavformat/microdvddec.c')
-rw-r--r-- | libavformat/microdvddec.c | 42 |
1 files changed, 39 insertions, 3 deletions
diff --git a/libavformat/microdvddec.c b/libavformat/microdvddec.c index 4055ee105a..5e37bc38a3 100644 --- a/libavformat/microdvddec.c +++ b/libavformat/microdvddec.c @@ -29,6 +29,8 @@ typedef struct { uint8_t lines[3][MAX_LINESIZE]; int64_t pos[3]; + AVPacket last_pkt; + int last_pkt_ready; } MicroDVDContext; @@ -96,7 +98,7 @@ static int get_duration(const char *buf) if (sscanf(buf, "{%d}{%d}", &frame_start, &frame_end) == 2) return frame_end - frame_start; - return 0; + return -1; } static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -106,6 +108,13 @@ static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt) int64_t pos = avio_tell(s->pb); int i, len = 0, res = AVERROR_EOF; + // last packet has its duration set but couldn't be raised earlier + if (microdvd->last_pkt_ready) { + *pkt = microdvd->last_pkt; + microdvd->last_pkt_ready = 0; + return 0; + } + for (i=0; i<FF_ARRAY_ELEMS(microdvd->lines); i++) { if (microdvd->lines[i][0]) { strcpy(buffer, microdvd->lines[i]); @@ -118,13 +127,40 @@ static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt) if (!len) len = ff_get_line(s->pb, buffer, sizeof(buffer)); - if (buffer[0] && !(res = av_new_packet(pkt, len))) { + if (microdvd->last_pkt.duration == -1 && !buffer[0]) { + // if the previous subtitle line had no duration, last until the end of + // the presentation + microdvd->last_pkt.duration = 0; + *pkt = microdvd->last_pkt; + pkt->duration = -1; + res = 0; + } else if (buffer[0] && !(res = av_new_packet(pkt, len))) { memcpy(pkt->data, buffer, len); pkt->flags |= AV_PKT_FLAG_KEY; pkt->pos = pos; pkt->pts = pkt->dts = get_pts(buffer); - if (pkt->pts != AV_NOPTS_VALUE) // TODO: handle "{}" duration + + if (pkt->pts != AV_NOPTS_VALUE) { pkt->duration = get_duration(buffer); + if (microdvd->last_pkt.duration == -1) { + // previous packet wasn't raised because it was lacking the + // duration info, so set its duration with the new packet pts + // and raise it + AVPacket tmp_pkt; + + tmp_pkt = microdvd->last_pkt; + tmp_pkt.duration = pkt->pts - tmp_pkt.pts; + microdvd->last_pkt = *pkt; + microdvd->last_pkt_ready = pkt->duration != -1; + *pkt = tmp_pkt; + } else if (pkt->duration == -1) { + // no packet without duration queued, and current one is + // lacking the duration info, we need to parse another subtitle + // event. + microdvd->last_pkt = *pkt; + res = AVERROR(EAGAIN); + } + } } return res; } |