LCOV - code coverage report
Current view: top level - libavformat - microdvddec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 69 79 87.3 %
Date: 2017-12-15 11:05:35 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :  * MicroDVD subtitle demuxer
       3             :  * Copyright (c) 2010  Aurelien Jacobs <aurel@gnuage.org>
       4             :  * Copyright (c) 2012  Clément Bœsch <u pkh me>
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #include "avformat.h"
      24             : #include "internal.h"
      25             : #include "subtitles.h"
      26             : #include "libavutil/intreadwrite.h"
      27             : #include "libavutil/opt.h"
      28             : 
      29             : #define MAX_LINESIZE 2048
      30             : 
      31             : 
      32             : typedef struct {
      33             :     const AVClass *class;
      34             :     FFDemuxSubtitlesQueue q;
      35             :     AVRational frame_rate;
      36             : } MicroDVDContext;
      37             : 
      38             : 
      39        6130 : static int microdvd_probe(AVProbeData *p)
      40             : {
      41             :     unsigned char c;
      42        6130 :     const uint8_t *ptr = p->buf;
      43             :     int i;
      44             : 
      45        6130 :     if (AV_RB24(ptr) == 0xEFBBBF)
      46           8 :         ptr += 3;  /* skip UTF-8 BOM */
      47             : 
      48        6139 :     for (i=0; i<3; i++) {
      49       12268 :         if (sscanf(ptr, "{%*d}{}%c",     &c) != 1 &&
      50       12261 :             sscanf(ptr, "{%*d}{%*d}%c",  &c) != 1 &&
      51        6129 :             sscanf(ptr, "{DEFAULT}{}%c", &c) != 1)
      52        6127 :             return 0;
      53           9 :         ptr += ff_subtitles_next_line(ptr);
      54             :     }
      55           3 :     return AVPROBE_SCORE_MAX;
      56             : }
      57             : 
      58          70 : static int64_t get_pts(const char *buf)
      59             : {
      60             :     int frame;
      61             :     char c;
      62             : 
      63          70 :     if (sscanf(buf, "{%d}{%c", &frame, &c) == 2)
      64          70 :         return frame;
      65           0 :     return AV_NOPTS_VALUE;
      66             : }
      67             : 
      68          70 : static int get_duration(const char *buf)
      69             : {
      70             :     int frame_start, frame_end;
      71             : 
      72          70 :     if (sscanf(buf, "{%d}{%d}", &frame_start, &frame_end) == 2)
      73          60 :         return frame_end - frame_start;
      74          10 :     return -1;
      75             : }
      76             : 
      77             : static const char *bom = "\xEF\xBB\xBF";
      78             : 
      79           3 : static int microdvd_read_header(AVFormatContext *s)
      80             : {
      81           3 :     AVRational pts_info = (AVRational){ 2997, 125 };  /* default: 23.976 fps */
      82           3 :     MicroDVDContext *microdvd = s->priv_data;
      83           3 :     AVStream *st = avformat_new_stream(s, NULL);
      84           3 :     int i = 0;
      85             :     char line_buf[MAX_LINESIZE];
      86           3 :     int has_real_fps = 0;
      87             : 
      88           3 :     if (!st)
      89           0 :         return AVERROR(ENOMEM);
      90             : 
      91          80 :     while (!avio_feof(s->pb)) {
      92             :         char *p;
      93             :         AVPacket *sub;
      94          77 :         int64_t pos = avio_tell(s->pb);
      95          77 :         int len = ff_get_line(s->pb, line_buf, sizeof(line_buf));
      96          77 :         char *line = line_buf;
      97             : 
      98          77 :         if (!strncmp(line, bom, 3))
      99           0 :             line += 3;
     100          77 :         p = line;
     101             : 
     102          77 :         if (!len)
     103           3 :             break;
     104          74 :         line[strcspn(line, "\r\n")] = 0;
     105          74 :         if (i++ < 3) {
     106             :             int frame;
     107             :             double fps;
     108             :             char c;
     109             : 
     110          16 :             if ((sscanf(line, "{%d}{}%6lf",    &frame, &fps) == 2 ||
     111           7 :                  sscanf(line, "{%d}{%*d}%6lf", &frame, &fps) == 2)
     112           2 :                 && frame <= 1 && fps > 3 && fps < 100) {
     113           2 :                 pts_info = av_d2q(fps, 100000);
     114           2 :                 has_real_fps = 1;
     115           6 :                 continue;
     116             :             }
     117           7 :             if (!st->codecpar->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) {
     118           2 :                 st->codecpar->extradata = av_strdup(line + 11);
     119           2 :                 if (!st->codecpar->extradata)
     120           0 :                     return AVERROR(ENOMEM);
     121           2 :                 st->codecpar->extradata_size = strlen(st->codecpar->extradata) + 1;
     122           2 :                 continue;
     123             :             }
     124             :         }
     125             : #define SKIP_FRAME_ID                                       \
     126             :     p = strchr(p, '}');                                     \
     127             :     if (!p) {                                               \
     128             :         av_log(s, AV_LOG_WARNING, "Invalid event \"%s\""    \
     129             :                " at line %d\n", line, i);                   \
     130             :         continue;                                           \
     131             :     }                                                       \
     132             :     p++
     133          70 :         SKIP_FRAME_ID;
     134          70 :         SKIP_FRAME_ID;
     135          70 :         if (!*p)
     136           0 :             continue;
     137          70 :         sub = ff_subtitles_queue_insert(&microdvd->q, p, strlen(p), 0);
     138          70 :         if (!sub)
     139           0 :             return AVERROR(ENOMEM);
     140          70 :         sub->pos = pos;
     141          70 :         sub->pts = get_pts(line);
     142          70 :         sub->duration = get_duration(line);
     143             :     }
     144           3 :     ff_subtitles_queue_finalize(s, &microdvd->q);
     145           3 :     if (has_real_fps) {
     146             :         /* export the FPS info only if set in the file */
     147           2 :         microdvd->frame_rate = pts_info;
     148           1 :     } else if (microdvd->frame_rate.num) {
     149             :         /* fallback on user specified frame rate */
     150           0 :         pts_info = microdvd->frame_rate;
     151             :     }
     152           3 :     avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num);
     153           3 :     st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
     154           3 :     st->codecpar->codec_id   = AV_CODEC_ID_MICRODVD;
     155           3 :     return 0;
     156             : }
     157             : 
     158          73 : static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt)
     159             : {
     160          73 :     MicroDVDContext *microdvd = s->priv_data;
     161          73 :     return ff_subtitles_queue_read_packet(&microdvd->q, pkt);
     162             : }
     163             : 
     164           0 : static int microdvd_read_seek(AVFormatContext *s, int stream_index,
     165             :                              int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
     166             : {
     167           0 :     MicroDVDContext *microdvd = s->priv_data;
     168           0 :     return ff_subtitles_queue_seek(&microdvd->q, s, stream_index,
     169             :                                    min_ts, ts, max_ts, flags);
     170             : }
     171             : 
     172           3 : static int microdvd_read_close(AVFormatContext *s)
     173             : {
     174           3 :     MicroDVDContext *microdvd = s->priv_data;
     175           3 :     ff_subtitles_queue_clean(&microdvd->q);
     176           3 :     return 0;
     177             : }
     178             : 
     179             : 
     180             : #define OFFSET(x) offsetof(MicroDVDContext, x)
     181             : #define SD AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM
     182             : static const AVOption microdvd_options[] = {
     183             :     { "subfps", "set the movie frame rate fallback", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, SD },
     184             :     { NULL }
     185             : };
     186             : 
     187             : static const AVClass microdvd_class = {
     188             :     .class_name = "microdvddec",
     189             :     .item_name  = av_default_item_name,
     190             :     .option     = microdvd_options,
     191             :     .version    = LIBAVUTIL_VERSION_INT,
     192             : };
     193             : 
     194             : AVInputFormat ff_microdvd_demuxer = {
     195             :     .name           = "microdvd",
     196             :     .long_name      = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
     197             :     .priv_data_size = sizeof(MicroDVDContext),
     198             :     .read_probe     = microdvd_probe,
     199             :     .read_header    = microdvd_read_header,
     200             :     .read_packet    = microdvd_read_packet,
     201             :     .read_seek2     = microdvd_read_seek,
     202             :     .read_close     = microdvd_read_close,
     203             :     .priv_class     = &microdvd_class,
     204             : };

Generated by: LCOV version 1.13