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.
27 #include "libmpdemux/stheader.h"
28 #include "libvo/sub.h"
31 #include "subassconvert.h"
34 struct ass_track
*ass_track
;
35 bool incomplete_event
;
38 static void free_last_event(ASS_Track
*track
)
40 assert(track
->n_events
> 0);
41 ass_free_event(track
, track
->n_events
- 1);
45 static void init(struct sh_sub
*sh
, struct osd_state
*osd
)
47 struct sd_ass_priv
*ctx
;
49 if (sh
->initialized
) {
52 ctx
= talloc_zero(NULL
, struct sd_ass_priv
);
54 if (sh
->type
== 'a') {
55 ctx
->ass_track
= ass_new_track(ass_library
);
57 ass_process_codec_private(ctx
->ass_track
, sh
->extradata
,
60 ctx
->ass_track
= mp_ass_default_track(ass_library
);
63 assert(osd
->ass_track
== NULL
);
64 osd
->ass_track
= ctx
->ass_track
;
65 osd
->vsfilter_aspect
= sh
->type
== 'a';
66 osd
->ass_track_changed
= true;
69 static void decode(struct sh_sub
*sh
, struct osd_state
*osd
, void *data
,
70 int data_len
, double pts
, double duration
)
72 unsigned char *text
= data
;
73 struct sd_ass_priv
*ctx
= sh
->context
;
74 ASS_Track
*track
= ctx
->ass_track
;
76 if (sh
->type
== 'a') { // ssa/ass subs
77 ass_process_chunk(track
, data
, data_len
,
78 (long long)(pts
*1000 + 0.5),
79 (long long)(duration
*1000 + 0.5));
83 if (pts
== MP_NOPTS_VALUE
) {
84 mp_msg(MSGT_SUBREADER
, MSGL_WARN
, "Subtitle without pts, ignored\n");
87 long long ipts
= pts
* 1000 + 0.5;
88 long long iduration
= duration
* 1000 + 0.5;
89 if (ctx
->incomplete_event
) {
90 ctx
->incomplete_event
= false;
91 ASS_Event
*event
= track
->events
+ track
->n_events
- 1;
92 if (ipts
<= event
->Start
)
93 free_last_event(track
);
95 event
->Duration
= ipts
- event
->Start
;
97 // Note: we rely on there being guaranteed 0 bytes after data packets
98 int len
= strlen(text
);
100 // Some tracks use a whitespace (but not empty) packet to mark end
101 // of previous subtitle.
102 for (int i
= 0; i
< len
; i
++)
103 if (!strchr(" \f\n\r\t\v", text
[i
]))
104 goto not_all_whitespace
;
109 subassconvert_subrip(text
, buf
, sizeof(buf
));
110 for (int i
= 0; i
< track
->n_events
; i
++)
111 if (track
->events
[i
].Start
== ipts
112 && (duration
<= 0 || track
->events
[i
].Duration
== iduration
)
113 && strcmp(track
->events
[i
].Text
, buf
) == 0)
114 return; // We've already added this subtitle
117 ctx
->incomplete_event
= true;
119 int eid
= ass_alloc_event(track
);
120 ASS_Event
*event
= track
->events
+ eid
;
122 event
->Duration
= iduration
;
123 event
->Text
= strdup(buf
);
126 static void reset(struct sh_sub
*sh
, struct osd_state
*osd
)
128 struct sd_ass_priv
*ctx
= sh
->context
;
129 if (ctx
->incomplete_event
)
130 free_last_event(ctx
->ass_track
);
131 ctx
->incomplete_event
= false;
134 static void switch_off(struct sh_sub
*sh
, struct osd_state
*osd
)
137 osd
->ass_track
= NULL
;
140 static void uninit(struct sh_sub
*sh
)
142 struct sd_ass_priv
*ctx
= sh
->context
;
144 ass_free_track(ctx
->ass_track
);
148 const struct sd_functions sd_ass
= {
152 .switch_off
= switch_off
,