LCOV - code coverage report
Current view: top level - libavformat - subviewerdec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 80 90 88.9 %
Date: 2017-12-16 13:57:32 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012 Clément Bœsch
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : /**
      22             :  * @file
      23             :  * SubViewer subtitle demuxer
      24             :  * @see https://en.wikipedia.org/wiki/SubViewer
      25             :  */
      26             : 
      27             : #include "avformat.h"
      28             : #include "internal.h"
      29             : #include "subtitles.h"
      30             : #include "libavcodec/internal.h"
      31             : #include "libavutil/avstring.h"
      32             : #include "libavutil/bprint.h"
      33             : #include "libavutil/intreadwrite.h"
      34             : 
      35             : typedef struct {
      36             :     FFDemuxSubtitlesQueue q;
      37             : } SubViewerContext;
      38             : 
      39        6130 : static int subviewer_probe(AVProbeData *p)
      40             : {
      41             :     char c;
      42        6130 :     const unsigned char *ptr = p->buf;
      43             : 
      44        6130 :     if (AV_RB24(ptr) == 0xEFBBBF)
      45           8 :         ptr += 3;  /* skip UTF-8 BOM */
      46        6130 :     if (sscanf(ptr, "%*u:%*u:%*u.%*u,%*u:%*u:%*u.%*u%c", &c) == 1)
      47           0 :         return AVPROBE_SCORE_EXTENSION;
      48        6130 :     if (!strncmp(ptr, "[INFORMATION]", 13))
      49           1 :         return AVPROBE_SCORE_MAX/3;
      50        6129 :     return 0;
      51             : }
      52             : 
      53           9 : static int read_ts(const char *s, int64_t *start, int *duration)
      54             : {
      55             :     int64_t end;
      56             :     int hh1, mm1, ss1, ms1;
      57             :     int hh2, mm2, ss2, ms2;
      58             : 
      59           9 :     if (sscanf(s, "%u:%u:%u.%u,%u:%u:%u.%u",
      60             :                &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2) == 8) {
      61           3 :         end    = (hh2*3600LL + mm2*60LL + ss2) * 100LL + ms2;
      62           3 :         *start = (hh1*3600LL + mm1*60LL + ss1) * 100LL + ms1;
      63           3 :         *duration = end - *start;
      64           3 :         return 0;
      65             :     }
      66           6 :     return -1;
      67             : }
      68             : 
      69           1 : static int subviewer_read_header(AVFormatContext *s)
      70             : {
      71           1 :     SubViewerContext *subviewer = s->priv_data;
      72           1 :     AVStream *st = avformat_new_stream(s, NULL);
      73             :     AVBPrint header;
      74           1 :     int res = 0, new_event = 1;
      75           1 :     int64_t pts_start = AV_NOPTS_VALUE;
      76           1 :     int duration = -1;
      77           1 :     AVPacket *sub = NULL;
      78             : 
      79           1 :     if (!st)
      80           0 :         return AVERROR(ENOMEM);
      81           1 :     avpriv_set_pts_info(st, 64, 1, 100);
      82           1 :     st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
      83           1 :     st->codecpar->codec_id   = AV_CODEC_ID_SUBVIEWER;
      84             : 
      85           1 :     av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
      86             : 
      87           1 :     while (!avio_feof(s->pb)) {
      88             :         char line[2048];
      89          21 :         int64_t pos = 0;
      90          21 :         int len = ff_get_line(s->pb, line, sizeof(line));
      91             : 
      92          21 :         if (!len)
      93           1 :             break;
      94             : 
      95          20 :         line[strcspn(line, "\r\n")] = 0;
      96             : 
      97          20 :         if (line[0] == '[' && strncmp(line, "[br]", 4)) {
      98             : 
      99             :             /* ignore event style, XXX: add to side_data? */
     100          20 :             if (strstr(line, "[COLF]") || strstr(line, "[SIZE]") ||
     101          18 :                 strstr(line, "[FONT]") || strstr(line, "[STYLE]"))
     102           2 :                 continue;
     103             : 
     104          18 :             if (!st->codecpar->extradata) { // header not finalized yet
     105           8 :                 av_bprintf(&header, "%s\n", line);
     106           8 :                 if (!strncmp(line, "[END INFORMATION]", 17) || !strncmp(line, "[SUBTITLE]", 10)) {
     107             :                     /* end of header */
     108           1 :                     res = ff_bprint_to_codecpar_extradata(st->codecpar, &header);
     109           2 :                     if (res < 0)
     110           0 :                         goto end;
     111           7 :                 } else if (strncmp(line, "[INFORMATION]", 13)) {
     112             :                     /* assume file metadata at this point */
     113           6 :                     int i, j = 0;
     114             :                     char key[32], value[128];
     115             : 
     116          43 :                     for (i = 1; i < sizeof(key) - 1 && line[i] && line[i] != ']'; i++)
     117          37 :                         key[i - 1] = av_tolower(line[i]);
     118           6 :                     key[i - 1] = 0;
     119             : 
     120           6 :                     if (line[i] == ']')
     121           6 :                         i++;
     122          18 :                     while (line[i] == ' ')
     123           6 :                         i++;
     124          84 :                     while (j < sizeof(value) - 1 && line[i] && line[i] != ']')
     125          72 :                         value[j++] = line[i++];
     126           6 :                     value[j] = 0;
     127             : 
     128           6 :                     av_dict_set(&s->metadata, key, value, 0);
     129             :                 }
     130             :             }
     131           9 :         } else if (read_ts(line, &pts_start, &duration) >= 0) {
     132           3 :             new_event = 1;
     133           3 :             pos = avio_tell(s->pb);
     134           6 :         } else if (*line) {
     135           5 :             if (!new_event) {
     136           2 :                 sub = ff_subtitles_queue_insert(&subviewer->q, "\n", 1, 1);
     137           2 :                 if (!sub) {
     138           0 :                     res = AVERROR(ENOMEM);
     139           0 :                     goto end;
     140             :                 }
     141             :             }
     142           5 :             sub = ff_subtitles_queue_insert(&subviewer->q, line, strlen(line), !new_event);
     143           5 :             if (!sub) {
     144           0 :                 res = AVERROR(ENOMEM);
     145           0 :                 goto end;
     146             :             }
     147           5 :             if (new_event) {
     148           3 :                 sub->pos = pos;
     149           3 :                 sub->pts = pts_start;
     150           3 :                 sub->duration = duration;
     151             :             }
     152           5 :             new_event = 0;
     153             :         }
     154             :     }
     155             : 
     156           1 :     ff_subtitles_queue_finalize(s, &subviewer->q);
     157             : 
     158           1 : end:
     159           1 :     av_bprint_finalize(&header, NULL);
     160           1 :     return res;
     161             : }
     162             : 
     163           4 : static int subviewer_read_packet(AVFormatContext *s, AVPacket *pkt)
     164             : {
     165           4 :     SubViewerContext *subviewer = s->priv_data;
     166           4 :     return ff_subtitles_queue_read_packet(&subviewer->q, pkt);
     167             : }
     168             : 
     169           0 : static int subviewer_read_seek(AVFormatContext *s, int stream_index,
     170             :                                int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
     171             : {
     172           0 :     SubViewerContext *subviewer = s->priv_data;
     173           0 :     return ff_subtitles_queue_seek(&subviewer->q, s, stream_index,
     174             :                                    min_ts, ts, max_ts, flags);
     175             : }
     176             : 
     177           1 : static int subviewer_read_close(AVFormatContext *s)
     178             : {
     179           1 :     SubViewerContext *subviewer = s->priv_data;
     180           1 :     ff_subtitles_queue_clean(&subviewer->q);
     181           1 :     return 0;
     182             : }
     183             : 
     184             : AVInputFormat ff_subviewer_demuxer = {
     185             :     .name           = "subviewer",
     186             :     .long_name      = NULL_IF_CONFIG_SMALL("SubViewer subtitle format"),
     187             :     .priv_data_size = sizeof(SubViewerContext),
     188             :     .read_probe     = subviewer_probe,
     189             :     .read_header    = subviewer_read_header,
     190             :     .read_packet    = subviewer_read_packet,
     191             :     .read_seek2     = subviewer_read_seek,
     192             :     .read_close     = subviewer_read_close,
     193             :     .extensions     = "sub",
     194             : };

Generated by: LCOV version 1.13