Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * SSA/ASS demuxer
  3.  * Copyright (c) 2008 Michael Niedermayer
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. #include "avformat.h"
  23. #include "internal.h"
  24. #include "subtitles.h"
  25. #include "libavcodec/internal.h"
  26. #include "libavutil/bprint.h"
  27.  
  28. typedef struct ASSContext{
  29.     FFDemuxSubtitlesQueue q;
  30. }ASSContext;
  31.  
  32. static int ass_probe(AVProbeData *p)
  33. {
  34.     const char *header= "[Script Info]";
  35.  
  36.     if(   !memcmp(p->buf  , header, strlen(header))
  37.        || !memcmp(p->buf+3, header, strlen(header)))
  38.         return AVPROBE_SCORE_MAX;
  39.  
  40.     return 0;
  41. }
  42.  
  43. static int ass_read_close(AVFormatContext *s)
  44. {
  45.     ASSContext *ass = s->priv_data;
  46.     ff_subtitles_queue_clean(&ass->q);
  47.     return 0;
  48. }
  49.  
  50. static int read_ts(const uint8_t *p, int64_t *start, int *duration)
  51. {
  52.     int64_t end;
  53.     int hh1, mm1, ss1, ms1;
  54.     int hh2, mm2, ss2, ms2;
  55.  
  56.     if (sscanf(p, "%*[^,],%d:%d:%d%*c%d,%d:%d:%d%*c%d",
  57.                &hh1, &mm1, &ss1, &ms1,
  58.                &hh2, &mm2, &ss2, &ms2) == 8) {
  59.         end    = (hh2*3600LL + mm2*60LL + ss2) * 100LL + ms2;
  60.         *start = (hh1*3600LL + mm1*60LL + ss1) * 100LL + ms1;
  61.         *duration = end - *start;
  62.         return 0;
  63.     }
  64.     return -1;
  65. }
  66.  
  67. static int64_t get_line(AVBPrint *buf, AVIOContext *pb)
  68. {
  69.     int64_t pos = avio_tell(pb);
  70.  
  71.     av_bprint_clear(buf);
  72.     for (;;) {
  73.         char c = avio_r8(pb);
  74.         if (!c)
  75.             break;
  76.         av_bprint_chars(buf, c, 1);
  77.         if (c == '\n')
  78.             break;
  79.     }
  80.     return pos;
  81. }
  82.  
  83. static int ass_read_header(AVFormatContext *s)
  84. {
  85.     ASSContext *ass = s->priv_data;
  86.     AVBPrint header, line;
  87.     int header_remaining, res = 0;
  88.     AVStream *st;
  89.  
  90.     st = avformat_new_stream(s, NULL);
  91.     if (!st)
  92.         return AVERROR(ENOMEM);
  93.     avpriv_set_pts_info(st, 64, 1, 100);
  94.     st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
  95.     st->codec->codec_id= AV_CODEC_ID_SSA;
  96.  
  97.     header_remaining= INT_MAX;
  98.  
  99.     av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
  100.     av_bprint_init(&line,   0, AV_BPRINT_SIZE_UNLIMITED);
  101.  
  102.     for (;;) {
  103.         int64_t pos = get_line(&line, s->pb);
  104.  
  105.         if (!line.str[0]) // EOF
  106.             break;
  107.  
  108.         if (!memcmp(line.str, "[Events]", 8))
  109.             header_remaining= 2;
  110.         else if (line.str[0]=='[')
  111.             header_remaining= INT_MAX;
  112.  
  113.         if (header_remaining) {
  114.             av_bprintf(&header, "%s", line.str);
  115.             header_remaining--;
  116.         } else {
  117.             int64_t ts_start = AV_NOPTS_VALUE;
  118.             int duration = -1;
  119.             AVPacket *sub;
  120.  
  121.             if (read_ts(line.str, &ts_start, &duration) < 0)
  122.                 continue;
  123.             sub = ff_subtitles_queue_insert(&ass->q, line.str, line.len, 0);
  124.             if (!sub) {
  125.                 res = AVERROR(ENOMEM);
  126.                 goto end;
  127.             }
  128.             sub->pos = pos;
  129.             sub->pts = ts_start;
  130.             sub->duration = duration;
  131.         }
  132.     }
  133.  
  134.     av_bprint_finalize(&line, NULL);
  135.  
  136.     res = avpriv_bprint_to_extradata(st->codec, &header);
  137.     if (res < 0)
  138.         goto end;
  139.  
  140.     ff_subtitles_queue_finalize(&ass->q);
  141.  
  142. end:
  143.     return res;
  144. }
  145.  
  146. static int ass_read_packet(AVFormatContext *s, AVPacket *pkt)
  147. {
  148.     ASSContext *ass = s->priv_data;
  149.     return ff_subtitles_queue_read_packet(&ass->q, pkt);
  150. }
  151.  
  152. static int ass_read_seek(AVFormatContext *s, int stream_index,
  153.                          int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
  154. {
  155.     ASSContext *ass = s->priv_data;
  156.     return ff_subtitles_queue_seek(&ass->q, s, stream_index,
  157.                                    min_ts, ts, max_ts, flags);
  158. }
  159.  
  160. AVInputFormat ff_ass_demuxer = {
  161.     .name           = "ass",
  162.     .long_name      = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
  163.     .priv_data_size = sizeof(ASSContext),
  164.     .read_probe     = ass_probe,
  165.     .read_header    = ass_read_header,
  166.     .read_packet    = ass_read_packet,
  167.     .read_close     = ass_read_close,
  168.     .read_seek2     = ass_read_seek,
  169. };
  170.