3 * Copyright (c) 2008 Michael Niedermayer
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * 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.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define MAX_LINESIZE 2000
26 typedef struct ASSContext
{
27 uint8_t *event_buffer
;
29 unsigned int event_count
;
30 unsigned int event_index
;
33 static void get_line(ByteIOContext
*s
, char *buf
, int maxlen
)
42 }while(c
!= '\n' && c
);
47 static int probe(AVProbeData
*p
)
49 const char *header
= "[Script Info]";
51 if( !memcmp(p
->buf
, header
, strlen(header
))
52 || !memcmp(p
->buf
+3, header
, strlen(header
)))
53 return AVPROBE_SCORE_MAX
;
58 static int read_close(AVFormatContext
*s
)
60 ASSContext
*ass
= s
->priv_data
;
62 av_freep(&ass
->event_buffer
);
63 av_freep(&ass
->event
);
68 static int64_t get_pts(const uint8_t *p
)
70 int hour
, min
, sec
, hsec
;
72 if(sscanf(p
, "%*[^,],%d:%d:%d%*c%d", &hour
, &min
, &sec
, &hsec
) != 4)
73 return AV_NOPTS_VALUE
;
75 // av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d [%s]\n", i, hour, min, sec, hsec, p);
83 static int event_cmp(uint8_t **a
, uint8_t **b
)
85 return get_pts(*a
) - get_pts(*b
);
88 static int read_header(AVFormatContext
*s
, AVFormatParameters
*ap
)
90 int i
, header_remaining
;
91 ASSContext
*ass
= s
->priv_data
;
92 ByteIOContext
*pb
= s
->pb
;
95 uint8_t *p
, **dst
[2]={0};
98 st
= av_new_stream(s
, 0);
101 av_set_pts_info(st
, 64, 1, 100);
102 st
->codec
->codec_type
= CODEC_TYPE_SUBTITLE
;
103 st
->codec
->codec_id
= CODEC_ID_SSA
;
105 header_remaining
= INT_MAX
;
106 dst
[0] = &st
->codec
->extradata
;
107 dst
[1] = &ass
->event_buffer
;
108 while(!url_feof(pb
)){
109 uint8_t line
[MAX_LINESIZE
];
111 get_line(pb
, line
, sizeof(line
));
113 if(!memcmp(line
, "[Events]", 8))
115 else if(line
[0]=='[')
116 header_remaining
= INT_MAX
;
118 i
= header_remaining
==0;
120 if(i
&& get_pts(line
) == AV_NOPTS_VALUE
)
123 p
= av_fast_realloc(*(dst
[i
]), &allocated
[i
], pos
[i
]+MAX_LINESIZE
);
127 memcpy(p
+ pos
[i
], line
, strlen(line
)+1);
128 pos
[i
] += strlen(line
);
129 if(i
) ass
->event_count
++;
130 else header_remaining
--;
132 st
->codec
->extradata_size
= pos
[0];
134 if(ass
->event_count
>= UINT_MAX
/ sizeof(*ass
->event
))
137 ass
->event
= av_malloc(ass
->event_count
* sizeof(*ass
->event
));
138 p
= ass
->event_buffer
;
139 for(i
=0; i
<ass
->event_count
; i
++){
141 while(*p
&& *p
!= '\n')
146 qsort(ass
->event
, ass
->event_count
, sizeof(*ass
->event
), (void*)event_cmp
);
156 static int read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
158 ASSContext
*ass
= s
->priv_data
;
161 if(ass
->event_index
>= ass
->event_count
)
164 p
= ass
->event
[ ass
->event_index
];
166 end
= strchr(p
, '\n');
167 av_new_packet(pkt
, end
? end
-p
+1 : strlen(p
));
168 pkt
->flags
|= PKT_FLAG_KEY
;
169 pkt
->pos
= p
- ass
->event_buffer
+ s
->streams
[0]->codec
->extradata_size
;
170 pkt
->pts
= pkt
->dts
= get_pts(p
);
171 memcpy(pkt
->data
, p
, pkt
->size
);
178 AVInputFormat ass_demuxer
= {
180 NULL_IF_CONFIG_SMALL("SSA/ASS format"),