ao_pulse: support native mute control
[mplayer.git] / sub / sd_ass.c
blob69587646e4f9d2336f124c38263a4d84e5c9b348
1 /*
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.
19 #include <stdlib.h>
20 #include <ass/ass.h>
21 #include <assert.h>
22 #include <string.h>
24 #include "talloc.h"
26 #include "mpcommon.h"
27 #include "mp_msg.h"
28 #include "libmpdemux/stheader.h"
29 #include "sub.h"
30 #include "ass_mp.h"
31 #include "sd.h"
32 #include "subassconvert.h"
34 struct sd_ass_priv {
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);
43 track->n_events--;
46 static void init(struct sh_sub *sh, struct osd_state *osd)
48 struct sd_ass_priv *ctx;
50 if (sh->initialized) {
51 ctx = sh->context;
52 } else {
53 ctx = talloc_zero(NULL, struct sd_ass_priv);
54 sh->context = ctx;
55 if (sh->type == 'a') {
56 ctx->ass_track = ass_new_track(osd->ass_library);
57 if (sh->extradata)
58 ass_process_codec_private(ctx->ass_track, sh->extradata,
59 sh->extradata_len);
60 } else
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));
81 return;
83 // plaintext subs
84 if (pts == MP_NOPTS_VALUE) {
85 mp_msg(MSGT_SUBREADER, MSGL_WARN, "Subtitle without pts, ignored\n");
86 return;
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);
95 else
96 event->Duration = ipts - event->Start;
98 // Note: we rely on there being guaranteed 0 bytes after data packets
99 int len = strlen(text);
100 if (len < 5) {
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;
106 return;
108 not_all_whitespace:;
109 char buf[500];
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
116 if (duration <= 0) {
117 iduration = 10000;
118 ctx->incomplete_event = true;
120 int eid = ass_alloc_event(track);
121 ASS_Event *event = track->events + eid;
122 event->Start = ipts;
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)
138 reset(sh, 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);
147 talloc_free(ctx);
150 const struct sd_functions sd_ass = {
151 .init = init,
152 .decode = decode,
153 .reset = reset,
154 .switch_off = switch_off,
155 .uninit = uninit,