Subversion Repositories Kolibri OS

Rev

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

  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.  
  28. #define MAX_LINESIZE 2048
  29.  
  30.  
  31. typedef struct {
  32.     FFDemuxSubtitlesQueue q;
  33. } MicroDVDContext;
  34.  
  35.  
  36. static int microdvd_probe(AVProbeData *p)
  37. {
  38.     unsigned char c;
  39.     const uint8_t *ptr = p->buf;
  40.     int i;
  41.  
  42.     if (AV_RB24(ptr) == 0xEFBBBF)
  43.         ptr += 3;  /* skip UTF-8 BOM */
  44.  
  45.     for (i=0; i<3; i++) {
  46.         if (sscanf(ptr, "{%*d}{}%c",     &c) != 1 &&
  47.             sscanf(ptr, "{%*d}{%*d}%c",  &c) != 1 &&
  48.             sscanf(ptr, "{DEFAULT}{}%c", &c) != 1)
  49.             return 0;
  50.         ptr += ff_subtitles_next_line(ptr);
  51.     }
  52.     return AVPROBE_SCORE_MAX;
  53. }
  54.  
  55. static int64_t get_pts(const char *buf)
  56. {
  57.     int frame;
  58.     char c;
  59.  
  60.     if (sscanf(buf, "{%d}{%c", &frame, &c) == 2)
  61.         return frame;
  62.     return AV_NOPTS_VALUE;
  63. }
  64.  
  65. static int get_duration(const char *buf)
  66. {
  67.     int frame_start, frame_end;
  68.  
  69.     if (sscanf(buf, "{%d}{%d}", &frame_start, &frame_end) == 2)
  70.         return frame_end - frame_start;
  71.     return -1;
  72. }
  73.  
  74. static int microdvd_read_header(AVFormatContext *s)
  75. {
  76.     AVRational pts_info = (AVRational){ 2997, 125 };  /* default: 23.976 fps */
  77.     MicroDVDContext *microdvd = s->priv_data;
  78.     AVStream *st = avformat_new_stream(s, NULL);
  79.     int i = 0;
  80.     char line[MAX_LINESIZE];
  81.  
  82.     if (!st)
  83.         return AVERROR(ENOMEM);
  84.  
  85.     while (!url_feof(s->pb)) {
  86.         char *p = line;
  87.         AVPacket *sub;
  88.         int64_t pos = avio_tell(s->pb);
  89.         int len = ff_get_line(s->pb, line, sizeof(line));
  90.  
  91.         if (!len)
  92.             break;
  93.         line[strcspn(line, "\r\n")] = 0;
  94.         if (i++ < 3) {
  95.             int frame;
  96.             double fps;
  97.             char c;
  98.  
  99.             if ((sscanf(line, "{%d}{}%6lf",    &frame, &fps) == 2 ||
  100.                  sscanf(line, "{%d}{%*d}%6lf", &frame, &fps) == 2)
  101.                 && frame <= 1 && fps > 3 && fps < 100)
  102.                 pts_info = av_d2q(fps, 100000);
  103.             if (!st->codec->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) {
  104.                 st->codec->extradata = av_strdup(line + 11);
  105.                 if (!st->codec->extradata)
  106.                     return AVERROR(ENOMEM);
  107.                 st->codec->extradata_size = strlen(st->codec->extradata) + 1;
  108.                 continue;
  109.             }
  110.         }
  111. #define SKIP_FRAME_ID                                       \
  112.     p = strchr(p, '}');                                     \
  113.     if (!p) {                                               \
  114.         av_log(s, AV_LOG_WARNING, "Invalid event \"%s\""    \
  115.                " at line %d\n", line, i);                   \
  116.         continue;                                           \
  117.     }                                                       \
  118.     p++
  119.         SKIP_FRAME_ID;
  120.         SKIP_FRAME_ID;
  121.         if (!*p)
  122.             continue;
  123.         sub = ff_subtitles_queue_insert(&microdvd->q, p, strlen(p), 0);
  124.         if (!sub)
  125.             return AVERROR(ENOMEM);
  126.         sub->pos = pos;
  127.         sub->pts = get_pts(line);
  128.         sub->duration = get_duration(line);
  129.     }
  130.     ff_subtitles_queue_finalize(&microdvd->q);
  131.     avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num);
  132.     st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
  133.     st->codec->codec_id   = AV_CODEC_ID_MICRODVD;
  134.     return 0;
  135. }
  136.  
  137. static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt)
  138. {
  139.     MicroDVDContext *microdvd = s->priv_data;
  140.     return ff_subtitles_queue_read_packet(&microdvd->q, pkt);
  141. }
  142.  
  143. static int microdvd_read_seek(AVFormatContext *s, int stream_index,
  144.                              int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
  145. {
  146.     MicroDVDContext *microdvd = s->priv_data;
  147.     return ff_subtitles_queue_seek(&microdvd->q, s, stream_index,
  148.                                    min_ts, ts, max_ts, flags);
  149. }
  150.  
  151. static int microdvd_read_close(AVFormatContext *s)
  152. {
  153.     MicroDVDContext *microdvd = s->priv_data;
  154.     ff_subtitles_queue_clean(&microdvd->q);
  155.     return 0;
  156. }
  157.  
  158. AVInputFormat ff_microdvd_demuxer = {
  159.     .name           = "microdvd",
  160.     .long_name      = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
  161.     .priv_data_size = sizeof(MicroDVDContext),
  162.     .read_probe     = microdvd_probe,
  163.     .read_header    = microdvd_read_header,
  164.     .read_packet    = microdvd_read_packet,
  165.     .read_seek2     = microdvd_read_seek,
  166.     .read_close     = microdvd_read_close,
  167. };
  168.