blob: 070b623ebf9d7f16c0e5381285fa55611da3cb9b [file] [log] [blame]
Clément Bœsch53640f42012-06-17 09:42:471/*
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 * SAMI subtitle demuxer
24 * @see http://msdn.microsoft.com/en-us/library/ms971327.aspx
25 */
26
27#include "avformat.h"
28#include "internal.h"
29#include "subtitles.h"
Clément Bœsch53640f42012-06-17 09:42:4730#include "libavutil/avstring.h"
31#include "libavutil/bprint.h"
Clément Bœsch53640f42012-06-17 09:42:4732
33typedef struct {
34 FFDemuxSubtitlesQueue q;
35} SAMIContext;
36
Carl Eugen Hoyos4d8875e2019-03-21 00:18:3737static int sami_probe(const AVProbeData *p)
Clément Bœsch53640f42012-06-17 09:42:4738{
wm4231a5142014-09-02 18:53:0839 char buf[6];
40 FFTextReader tr;
41 ff_text_init_buf(&tr, p->buf, p->buf_size);
42 ff_text_read(&tr, buf, sizeof(buf));
Clément Bœsch53640f42012-06-17 09:42:4743
wm4231a5142014-09-02 18:53:0844 return !strncmp(buf, "<SAMI>", 6) ? AVPROBE_SCORE_MAX : 0;
Clément Bœsch53640f42012-06-17 09:42:4745}
46
47static int sami_read_header(AVFormatContext *s)
48{
49 SAMIContext *sami = s->priv_data;
50 AVStream *st = avformat_new_stream(s, NULL);
51 AVBPrint buf, hdr_buf;
52 char c = 0;
53 int res = 0, got_first_sync_point = 0;
wm4231a5142014-09-02 18:53:0854 FFTextReader tr;
Carl Eugen Hoyos19a64312014-10-29 00:32:4455 ff_text_init_avio(s, &tr, s->pb);
Clément Bœsch53640f42012-06-17 09:42:4756
57 if (!st)
58 return AVERROR(ENOMEM);
59 avpriv_set_pts_info(st, 64, 1, 1000);
Derek Buitenhuis6f69f7a2016-04-10 19:58:1560 st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
61 st->codecpar->codec_id = AV_CODEC_ID_SAMI;
Clément Bœsch53640f42012-06-17 09:42:4762
63 av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
64 av_bprint_init(&hdr_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
65
wm4231a5142014-09-02 18:53:0866 while (!ff_text_eof(&tr)) {
Clément Bœsch53640f42012-06-17 09:42:4767 AVPacket *sub;
wm4231a5142014-09-02 18:53:0868 const int64_t pos = ff_text_pos(&tr) - (c != 0);
Yayoi1bb8a532015-08-30 14:24:4969 int is_sync, is_body, n = ff_smil_extract_next_text_chunk(&tr, &buf, &c);
Clément Bœsch53640f42012-06-17 09:42:4770
Reimar Döffingerc0f867b2023-06-21 18:06:0971 if (n < 0) {
72 res = n;
73 goto end;
74 }
Clément Bœsch53640f42012-06-17 09:42:4775 if (n == 0)
76 break;
77
Yayoi1bb8a532015-08-30 14:24:4978 is_body = !av_strncasecmp(buf.str, "</BODY", 6);
79 if (is_body) {
80 av_bprint_clear(&buf);
81 break;
82 }
83
Clément Bœsch53640f42012-06-17 09:42:4784 is_sync = !av_strncasecmp(buf.str, "<SYNC", 5);
85 if (is_sync)
86 got_first_sync_point = 1;
87
88 if (!got_first_sync_point) {
89 av_bprintf(&hdr_buf, "%s", buf.str);
90 } else {
Reimar Döffingerc0f867b2023-06-21 18:06:0991 sub = ff_subtitles_queue_insert_bprint(&sami->q, &buf, !is_sync);
Clément Bœsch53640f42012-06-17 09:42:4792 if (!sub) {
93 res = AVERROR(ENOMEM);
Michael Niedermayer1c880982021-02-22 19:44:3694 av_bprint_finalize(&hdr_buf, NULL);
Clément Bœsch53640f42012-06-17 09:42:4795 goto end;
96 }
97 if (is_sync) {
98 const char *p = ff_smil_get_attr_ptr(buf.str, "Start");
99 sub->pos = pos;
100 sub->pts = p ? strtol(p, NULL, 10) : 0;
Michael Niedermayer2014b012021-01-31 16:00:38101 if (sub->pts <= INT64_MIN/2 || sub->pts >= INT64_MAX/2) {
102 res = AVERROR_PATCHWELCOME;
Michael Niedermayer1c880982021-02-22 19:44:36103 av_bprint_finalize(&hdr_buf, NULL);
Michael Niedermayer2014b012021-01-31 16:00:38104 goto end;
105 }
106
Clément Bœsch53640f42012-06-17 09:42:47107 sub->duration = -1;
108 }
109 }
110 av_bprint_clear(&buf);
111 }
112
Derek Buitenhuis6f69f7a2016-04-10 19:58:15113 res = ff_bprint_to_codecpar_extradata(st->codecpar, &hdr_buf);
Clément Bœsch36e61e22012-12-29 21:09:59114 if (res < 0)
Clément Bœsch53640f42012-06-17 09:42:47115 goto end;
Clément Bœsch53640f42012-06-17 09:42:47116
Clément Bœschaf924fd2015-09-10 19:40:07117 ff_subtitles_queue_finalize(s, &sami->q);
Clément Bœsch53640f42012-06-17 09:42:47118
119end:
Clément Bœsch53640f42012-06-17 09:42:47120 av_bprint_finalize(&buf, NULL);
121 return res;
122}
123
Andreas Rheinhardtbc706842021-04-19 17:45:24124const AVInputFormat ff_sami_demuxer = {
Clément Bœsch53640f42012-06-17 09:42:47125 .name = "sami",
126 .long_name = NULL_IF_CONFIG_SMALL("SAMI subtitle format"),
127 .priv_data_size = sizeof(SAMIContext),
Andreas Rheinhardt7ae7d932020-03-21 17:31:06128 .flags_internal = FF_FMT_INIT_CLEANUP,
Clément Bœsch53640f42012-06-17 09:42:47129 .read_probe = sami_probe,
130 .read_header = sami_read_header,
Clément Bœsch53640f42012-06-17 09:42:47131 .extensions = "smi,sami",
Andreas Rheinhardtea5bdc82021-07-08 21:05:08132 .read_packet = ff_subtitles_read_packet,
133 .read_seek2 = ff_subtitles_read_seek,
134 .read_close = ff_subtitles_read_close,
Clément Bœsch53640f42012-06-17 09:42:47135};