2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "libmpdemux/stheader.h"
32 #include "subassconvert.h"
35 struct ass_track
*ass_track
;
36 bool incomplete_event
;
39 static void free_last_event(ASS_Track
*track
)
41 assert(track
->n_events
> 0);
42 ass_free_event(track
, track
->n_events
- 1);
46 static void init(struct sh_sub
*sh
, struct osd_state
*osd
)
48 struct sd_ass_priv
*ctx
;
50 if (sh
->initialized
) {
53 ctx
= talloc_zero(NULL
, struct sd_ass_priv
);
55 if (sh
->type
== 'a') {
56 ctx
->ass_track
= ass_new_track(osd
->ass_library
);
58 ass_process_codec_private(ctx
->ass_track
, sh
->extradata
,
61 ctx
->ass_track
= mp_ass_default_track(osd
->ass_library
, sh
->opts
);
64 assert(osd
->ass_track
== NULL
);
65 osd
->ass_track
= ctx
->ass_track
;
66 osd
->vsfilter_aspect
= sh
->type
== 'a';
67 osd
->ass_track_changed
= true;
70 static void decode(struct sh_sub
*sh
, struct osd_state
*osd
, void *data
,
71 int data_len
, double pts
, double duration
)
73 unsigned char *text
= data
;
74 struct sd_ass_priv
*ctx
= sh
->context
;
75 ASS_Track
*track
= ctx
->ass_track
;
77 if (sh
->type
== 'a') { // ssa/ass subs
78 ass_process_chunk(track
, data
, data_len
,
79 (long long)(pts
*1000 + 0.5),
80 (long long)(duration
*1000 + 0.5));
84 if (pts
== MP_NOPTS_VALUE
) {
85 mp_msg(MSGT_SUBREADER
, MSGL_WARN
, "Subtitle without pts, ignored\n");
88 long long ipts
= pts
* 1000 + 0.5;
89 long long iduration
= duration
* 1000 + 0.5;
90 if (ctx
->incomplete_event
) {
91 ctx
->incomplete_event
= false;
92 ASS_Event
*event
= track
->events
+ track
->n_events
- 1;
93 if (ipts
<= event
->Start
)
94 free_last_event(track
);
96 event
->Duration
= ipts
- event
->Start
;
98 // Note: we rely on there being guaranteed 0 bytes after data packets
99 int len
= strlen(text
);
101 // Some tracks use a whitespace (but not empty) packet to mark end
102 // of previous subtitle.
103 for (int i
= 0; i
< len
; i
++)
104 if (!strchr(" \f\n\r\t\v", text
[i
]))
105 goto not_all_whitespace
;
110 subassconvert_subrip(text
, buf
, sizeof(buf
));
111 for (int i
= 0; i
< track
->n_events
; i
++)
112 if (track
->events
[i
].Start
== ipts
113 && (duration
<= 0 || track
->events
[i
].Duration
== iduration
)
114 && strcmp(track
->events
[i
].Text
, buf
) == 0)
115 return; // We've already added this subtitle
118 ctx
->incomplete_event
= true;
120 int eid
= ass_alloc_event(track
);
121 ASS_Event
*event
= track
->events
+ eid
;
123 event
->Duration
= iduration
;
124 event
->Style
= track
->default_style
;
125 event
->Text
= strdup(buf
);
128 static void reset(struct sh_sub
*sh
, struct osd_state
*osd
)
130 struct sd_ass_priv
*ctx
= sh
->context
;
131 if (ctx
->incomplete_event
)
132 free_last_event(ctx
->ass_track
);
133 ctx
->incomplete_event
= false;
136 static void switch_off(struct sh_sub
*sh
, struct osd_state
*osd
)
139 osd
->ass_track
= NULL
;
142 static void uninit(struct sh_sub
*sh
)
144 struct sd_ass_priv
*ctx
= sh
->context
;
146 ass_free_track(ctx
->ass_track
);
150 const struct sd_functions sd_ass
= {
154 .switch_off
= switch_off
,