Merge commit '25c7db7cc99d74fe6fb56a6fd52c9b5f1591e448'
[ffmpeg.git] / libavformat / jacosubdec.c
index 67f4c37..e2cbaad 100644 (file)
 
 #include "avformat.h"
 #include "internal.h"
+#include "subtitles.h"
+#include "libavcodec/internal.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)
@@ -67,10 +60,10 @@ static int jacosub_probe(AVProbeData *p)
             ptr++;
         if (*ptr != '#' && *ptr != '\n') {
             if (timed_line(ptr))
-                return AVPROBE_SCORE_MAX/2 + 1;
+                return AVPROBE_SCORE_EXTENSION + 1;
             return 0;
         }
-        ptr += strcspn(ptr, "\n") + 1;
+        ptr += ff_subtitles_next_line(ptr);
     }
     return 0;
 }
@@ -101,41 +94,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 +152,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;
@@ -174,14 +160,14 @@ static int jacosub_read_header(AVFormatContext *s)
     JACOsubContext *jacosub = s->priv_data;
     int shift_set = 0; // only the first shift matters
     int merge_line = 0;
-    int i;
+    int i, ret;
 
     AVStream *st = avformat_new_stream(s, NULL);
     if (!st)
         return AVERROR(ENOMEM);
     avpriv_set_pts_info(st, 64, 1, 100);
     st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
-    st->codec->codec_id   = CODEC_ID_JACOSUB;
+    st->codec->codec_id   = AV_CODEC_ID_JACOSUB;
 
     jacosub->timeres = 30;
 
@@ -191,41 +177,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;
         }
 
@@ -256,43 +220,42 @@ static int jacosub_read_header(AVFormatContext *s)
             break;
         case 'T': // ...but must be placed after TIMERES
             jacosub->timeres = strtol(p, NULL, 10);
-            av_bprintf(&header, "#T %s", p);
+            if (!jacosub->timeres)
+                jacosub->timeres = 30;
+            else
+                av_bprintf(&header, "#T %s", p);
             break;
         }
     }
 
     /* general/essential directives in the extradata */
-    av_bprint_finalize(&header, (char **)&st->codec->extradata);
-    st->codec->extradata_size = header.len + 1;
+    ret = avpriv_bprint_to_extradata(st->codec, &header);
+    if (ret < 0)
+        return ret;
 
     /* 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);
+}
+
+static int jacosub_read_seek(AVFormatContext *s, int stream_index,
+                             int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+    JACOsubContext *jacosub = s->priv_data;
+    return ff_subtitles_queue_seek(&jacosub->q, s, stream_index,
+                                   min_ts, ts, max_ts, flags);
 }
 
 AVInputFormat ff_jacosub_demuxer = {
@@ -302,6 +265,6 @@ AVInputFormat ff_jacosub_demuxer = {
     .read_probe     = jacosub_probe,
     .read_header    = jacosub_read_header,
     .read_packet    = jacosub_read_packet,
+    .read_seek2     = jacosub_read_seek,
     .read_close     = jacosub_read_close,
-    .flags          = AVFMT_GENERIC_INDEX,
 };