ffmpeg / libavformat / assdec.c @ 56a10009
History | View | Annotate | Download (5.82 KB)
1 | de3ae185 | Michael Niedermayer | /*
|
---|---|---|---|
2 | * SSA/ASS demuxer
|
||
3 | * Copyright (c) 2008 Michael Niedermayer
|
||
4 | *
|
||
5 | 2912e87a | Mans Rullgard | * This file is part of Libav.
|
6 | de3ae185 | Michael Niedermayer | *
|
7 | 2912e87a | Mans Rullgard | * Libav is free software; you can redistribute it and/or
|
8 | de3ae185 | Michael Niedermayer | * modify it under the terms of the GNU Lesser General Public
|
9 | * License as published by the Free Software Foundation; either
|
||
10 | * version 2.1 of the License, or (at your option) any later version.
|
||
11 | *
|
||
12 | 2912e87a | Mans Rullgard | * Libav is distributed in the hope that it will be useful,
|
13 | de3ae185 | Michael Niedermayer | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
15 | * Lesser General Public License for more details.
|
||
16 | *
|
||
17 | * You should have received a copy of the GNU Lesser General Public
|
||
18 | 2912e87a | Mans Rullgard | * License along with Libav; if not, write to the Free Software
|
19 | de3ae185 | Michael Niedermayer | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
20 | */
|
||
21 | |||
22 | #include "avformat.h" |
||
23 | 7c892951 | Aurelien Jacobs | #include "internal.h" |
24 | de3ae185 | Michael Niedermayer | |
25 | #define MAX_LINESIZE 2000 |
||
26 | |||
27 | typedef struct ASSContext{ |
||
28 | uint8_t *event_buffer; |
||
29 | uint8_t **event; |
||
30 | unsigned int event_count; |
||
31 | unsigned int event_index; |
||
32 | }ASSContext; |
||
33 | |||
34 | static int probe(AVProbeData *p) |
||
35 | { |
||
36 | const char *header= "[Script Info]"; |
||
37 | |||
38 | if( !memcmp(p->buf , header, strlen(header))
|
||
39 | || !memcmp(p->buf+3, header, strlen(header)))
|
||
40 | return AVPROBE_SCORE_MAX;
|
||
41 | |||
42 | return 0; |
||
43 | } |
||
44 | |||
45 | static int read_close(AVFormatContext *s) |
||
46 | { |
||
47 | ASSContext *ass = s->priv_data; |
||
48 | |||
49 | av_freep(&ass->event_buffer); |
||
50 | av_freep(&ass->event); |
||
51 | |||
52 | return 0; |
||
53 | } |
||
54 | |||
55 | static int64_t get_pts(const uint8_t *p) |
||
56 | { |
||
57 | int hour, min, sec, hsec;
|
||
58 | |||
59 | if(sscanf(p, "%*[^,],%d:%d:%d%*c%d", &hour, &min, &sec, &hsec) != 4) |
||
60 | return AV_NOPTS_VALUE;
|
||
61 | |||
62 | // av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d [%s]\n", i, hour, min, sec, hsec, p);
|
||
63 | |||
64 | min+= 60*hour;
|
||
65 | sec+= 60*min;
|
||
66 | |||
67 | return sec*100+hsec; |
||
68 | } |
||
69 | |||
70 | static int event_cmp(uint8_t **a, uint8_t **b) |
||
71 | { |
||
72 | return get_pts(*a) - get_pts(*b);
|
||
73 | } |
||
74 | |||
75 | static int read_header(AVFormatContext *s, AVFormatParameters *ap) |
||
76 | { |
||
77 | 8a810ccb | Aurelien Jacobs | int i, len, header_remaining;
|
78 | de3ae185 | Michael Niedermayer | ASSContext *ass = s->priv_data; |
79 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
80 | de3ae185 | Michael Niedermayer | AVStream *st; |
81 | int allocated[2]={0}; |
||
82 | uint8_t *p, **dst[2]={0}; |
||
83 | int pos[2]={0}; |
||
84 | |||
85 | st = av_new_stream(s, 0);
|
||
86 | if (!st)
|
||
87 | return -1; |
||
88 | av_set_pts_info(st, 64, 1, 100); |
||
89 | 72415b2a | Stefano Sabatini | st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; |
90 | de3ae185 | Michael Niedermayer | st->codec->codec_id= CODEC_ID_SSA; |
91 | |||
92 | header_remaining= INT_MAX; |
||
93 | dst[0] = &st->codec->extradata;
|
||
94 | dst[1] = &ass->event_buffer;
|
||
95 | 66e5b1df | Anton Khirnov | while(!pb->eof_reached){
|
96 | de3ae185 | Michael Niedermayer | uint8_t line[MAX_LINESIZE]; |
97 | |||
98 | 8a810ccb | Aurelien Jacobs | len = ff_get_line(pb, line, sizeof(line));
|
99 | de3ae185 | Michael Niedermayer | |
100 | if(!memcmp(line, "[Events]", 8)) |
||
101 | header_remaining= 2;
|
||
102 | else if(line[0]=='[') |
||
103 | header_remaining= INT_MAX; |
||
104 | |||
105 | i= header_remaining==0;
|
||
106 | |||
107 | if(i && get_pts(line) == AV_NOPTS_VALUE)
|
||
108 | continue;
|
||
109 | |||
110 | p = av_fast_realloc(*(dst[i]), &allocated[i], pos[i]+MAX_LINESIZE); |
||
111 | if(!p)
|
||
112 | goto fail;
|
||
113 | *(dst[i])= p; |
||
114 | 8a810ccb | Aurelien Jacobs | memcpy(p + pos[i], line, len+1);
|
115 | pos[i] += len; |
||
116 | de3ae185 | Michael Niedermayer | if(i) ass->event_count++;
|
117 | else header_remaining--;
|
||
118 | } |
||
119 | st->codec->extradata_size= pos[0];
|
||
120 | |||
121 | if(ass->event_count >= UINT_MAX / sizeof(*ass->event)) |
||
122 | goto fail;
|
||
123 | |||
124 | ass->event= av_malloc(ass->event_count * sizeof(*ass->event));
|
||
125 | p= ass->event_buffer; |
||
126 | for(i=0; i<ass->event_count; i++){ |
||
127 | ass->event[i]= p; |
||
128 | while(*p && *p != '\n') |
||
129 | p++; |
||
130 | 5c8a1d19 | Michael Niedermayer | p++; |
131 | de3ae185 | Michael Niedermayer | } |
132 | |||
133 | 8ba31141 | Michael Niedermayer | qsort(ass->event, ass->event_count, sizeof(*ass->event), (void*)event_cmp); |
134 | de3ae185 | Michael Niedermayer | |
135 | return 0; |
||
136 | |||
137 | fail:
|
||
138 | read_close(s); |
||
139 | |||
140 | return -1; |
||
141 | } |
||
142 | |||
143 | static int read_packet(AVFormatContext *s, AVPacket *pkt) |
||
144 | { |
||
145 | ASSContext *ass = s->priv_data; |
||
146 | 5c8a1d19 | Michael Niedermayer | uint8_t *p, *end; |
147 | de3ae185 | Michael Niedermayer | |
148 | if(ass->event_index >= ass->event_count)
|
||
149 | return AVERROR(EIO);
|
||
150 | |||
151 | p= ass->event[ ass->event_index ]; |
||
152 | |||
153 | 5c8a1d19 | Michael Niedermayer | end= strchr(p, '\n');
|
154 | av_new_packet(pkt, end ? end-p+1 : strlen(p));
|
||
155 | cc947f04 | Jean-Daniel Dupas | pkt->flags |= AV_PKT_FLAG_KEY; |
156 | de3ae185 | Michael Niedermayer | pkt->pos= p - ass->event_buffer + s->streams[0]->codec->extradata_size;
|
157 | pkt->pts= pkt->dts= get_pts(p); |
||
158 | memcpy(pkt->data, p, pkt->size); |
||
159 | |||
160 | ass->event_index++; |
||
161 | |||
162 | return 0; |
||
163 | } |
||
164 | |||
165 | ac066b83 | Aurelien Jacobs | static int read_seek2(AVFormatContext *s, int stream_index, |
166 | int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
|
||
167 | { |
||
168 | ASSContext *ass = s->priv_data; |
||
169 | |||
170 | if (flags & AVSEEK_FLAG_BYTE) {
|
||
171 | return AVERROR_NOTSUPP;
|
||
172 | } else if (flags & AVSEEK_FLAG_FRAME) { |
||
173 | if (ts < 0 || ts >= ass->event_count) |
||
174 | return AVERROR(ERANGE);
|
||
175 | ass->event_index = ts; |
||
176 | } else {
|
||
177 | int i, idx = -1; |
||
178 | int64_t min_ts_diff = INT64_MAX; |
||
179 | if (stream_index == -1) { |
||
180 | AVRational time_base = s->streams[0]->time_base;
|
||
181 | ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); |
||
182 | min_ts = av_rescale_rnd(min_ts, time_base.den, |
||
183 | time_base.num * (int64_t)AV_TIME_BASE, |
||
184 | AV_ROUND_UP); |
||
185 | max_ts = av_rescale_rnd(max_ts, time_base.den, |
||
186 | time_base.num * (int64_t)AV_TIME_BASE, |
||
187 | AV_ROUND_DOWN); |
||
188 | } |
||
189 | /* TODO: ass->event[] is sorted by pts so we could do a binary search */
|
||
190 | for (i=0; i<ass->event_count; i++) { |
||
191 | int64_t pts = get_pts(ass->event[i]); |
||
192 | int64_t ts_diff = FFABS(pts - ts); |
||
193 | if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
|
||
194 | min_ts_diff = ts_diff; |
||
195 | idx = i; |
||
196 | } |
||
197 | } |
||
198 | if (idx < 0) |
||
199 | return AVERROR(ERANGE);
|
||
200 | ass->event_index = idx; |
||
201 | } |
||
202 | return 0; |
||
203 | } |
||
204 | |||
205 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_ass_demuxer = { |
206 | 87d69d32 | Aurelien Jacobs | .name = "ass",
|
207 | .long_name = NULL_IF_CONFIG_SMALL("Advanced SubStation Alpha subtitle format"),
|
||
208 | .priv_data_size = sizeof(ASSContext),
|
||
209 | .read_probe = probe, |
||
210 | .read_header = read_header, |
||
211 | .read_packet = read_packet, |
||
212 | .read_close = read_close, |
||
213 | .read_seek2 = read_seek2, |
||
214 | de3ae185 | Michael Niedermayer | }; |