00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 #include "libavutil/avstring.h"
00023 #include "libavutil/common.h"
00024 #include "libavutil/parseutils.h"
00025 #include "avcodec.h"
00026 #include "ass.h"
00027 
00028 static int html_color_parse(AVCodecContext *avctx, const char *str)
00029 {
00030     uint8_t rgba[4];
00031     if (av_parse_color(rgba, str, strcspn(str, "\" >"), avctx) < 0)
00032         return -1;
00033     return rgba[0] | rgba[1] << 8 | rgba[2] << 16;
00034 }
00035 
00036 enum {
00037     PARAM_UNKNOWN = -1,
00038     PARAM_SIZE,
00039     PARAM_COLOR,
00040     PARAM_FACE,
00041     PARAM_NUMBER
00042 };
00043 
00044 typedef struct {
00045     char tag[128];
00046     char param[PARAM_NUMBER][128];
00047 } SrtStack;
00048 
00049 static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
00050                               const char *in, int x1, int y1, int x2, int y2)
00051 {
00052     char c, *param, buffer[128], tmp[128];
00053     int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0;
00054     SrtStack stack[16];
00055 
00056     stack[0].tag[0] = 0;
00057     strcpy(stack[0].param[PARAM_SIZE],  "{\\fs}");
00058     strcpy(stack[0].param[PARAM_COLOR], "{\\c}");
00059     strcpy(stack[0].param[PARAM_FACE],  "{\\fn}");
00060 
00061     if (x1 >= 0 && y1 >= 0) {
00062         if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1))
00063             snprintf(out, out_end-out,
00064                             "{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2);
00065         else
00066             snprintf(out, out_end-out, "{\\an1}{\\pos(%d,%d)}", x1, y1);
00067         out += strlen(out);
00068     }
00069 
00070     for (; out < out_end && !end && *in; in++) {
00071         switch (*in) {
00072         case '\r':
00073             break;
00074         case '\n':
00075             if (line_start) {
00076                 end = 1;
00077                 break;
00078             }
00079             while (out[-1] == ' ')
00080                 out--;
00081             snprintf(out, out_end-out, "\\N");
00082             if(out<out_end) out += strlen(out);
00083             line_start = 1;
00084             break;
00085         case ' ':
00086             if (!line_start)
00087                 *out++ = *in;
00088             break;
00089         case '{':    
00090 
00091             an += sscanf(in, "{\\an%*1u}%c", &c) == 1;
00092             if ((an != 1 && sscanf(in, "{\\%*[^}]}%n%c", &len, &c) > 0) ||
00093                 sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n%c", &len, &c) > 0) {
00094                 in += len - 1;
00095             } else
00096                 *out++ = *in;
00097             break;
00098         case '<':
00099             tag_close = in[1] == '/';
00100             if (sscanf(in+tag_close+1, "%127[^>]>%n%c", buffer, &len,&c) >= 2) {
00101                 if ((param = strchr(buffer, ' ')))
00102                     *param++ = 0;
00103                 if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) ||
00104                     ( tag_close && sptr > 0 && !strcmp(stack[sptr-1].tag, buffer))) {
00105                     int i, j, unknown = 0;
00106                     in += len + tag_close;
00107                     if (!tag_close)
00108                         memset(stack+sptr, 0, sizeof(*stack));
00109                     if (!strcmp(buffer, "font")) {
00110                         if (tag_close) {
00111                             for (i=PARAM_NUMBER-1; i>=0; i--)
00112                                 if (stack[sptr-1].param[i][0])
00113                                     for (j=sptr-2; j>=0; j--)
00114                                         if (stack[j].param[i][0]) {
00115                                             snprintf(out, out_end-out,
00116                                                             "%s", stack[j].param[i]);
00117                                             if(out<out_end) out += strlen(out);
00118                                             break;
00119                                         }
00120                         } else {
00121                             while (param) {
00122                                 if (!strncmp(param, "size=", 5)) {
00123                                     unsigned font_size;
00124                                     param += 5 + (param[5] == '"');
00125                                     if (sscanf(param, "%u", &font_size) == 1) {
00126                                         snprintf(stack[sptr].param[PARAM_SIZE],
00127                                              sizeof(stack[0].param[PARAM_SIZE]),
00128                                              "{\\fs%u}", font_size);
00129                                     }
00130                                 } else if (!strncmp(param, "color=", 6)) {
00131                                     param += 6 + (param[6] == '"');
00132                                     snprintf(stack[sptr].param[PARAM_COLOR],
00133                                          sizeof(stack[0].param[PARAM_COLOR]),
00134                                          "{\\c&H%X&}",
00135                                          html_color_parse(avctx, param));
00136                                 } else if (!strncmp(param, "face=", 5)) {
00137                                     param += 5 + (param[5] == '"');
00138                                     len = strcspn(param,
00139                                                   param[-1] == '"' ? "\"" :" ");
00140                                     av_strlcpy(tmp, param,
00141                                                FFMIN(sizeof(tmp), len+1));
00142                                     param += len;
00143                                     snprintf(stack[sptr].param[PARAM_FACE],
00144                                              sizeof(stack[0].param[PARAM_FACE]),
00145                                              "{\\fn%s}", tmp);
00146                                 }
00147                                 if ((param = strchr(param, ' ')))
00148                                     param++;
00149                             }
00150                             for (i=0; i<PARAM_NUMBER; i++)
00151                                 if (stack[sptr].param[i][0]) {
00152                                     snprintf(out, out_end-out,
00153                                                     "%s", stack[sptr].param[i]);
00154                                     if(out<out_end) out += strlen(out);
00155                                 }
00156                         }
00157                     } else if (!buffer[1] && strspn(buffer, "bisu") == 1) {
00158                         snprintf(out, out_end-out,
00159                                         "{\\%c%d}", buffer[0], !tag_close);
00160                         if(out<out_end) out += strlen(out);
00161                     } else {
00162                         unknown = 1;
00163                         snprintf(tmp, sizeof(tmp), "</%s>", buffer);
00164                     }
00165                     if (tag_close) {
00166                         sptr--;
00167                     } else if (unknown && !strstr(in, tmp)) {
00168                         in -= len + tag_close;
00169                         *out++ = *in;
00170                     } else
00171                         av_strlcpy(stack[sptr++].tag, buffer,
00172                                    sizeof(stack[0].tag));
00173                     break;
00174                 }
00175             }
00176         default:
00177             *out++ = *in;
00178             break;
00179         }
00180         if (*in != ' ' && *in != '\r' && *in != '\n')
00181             line_start = 0;
00182     }
00183 
00184     out = FFMIN(out, out_end-3);
00185     while (!strncmp(out-2, "\\N", 2))
00186         out -= 2;
00187     while (out[-1] == ' ')
00188         out--;
00189     snprintf(out, out_end-out, "\r\n");
00190     return in;
00191 }
00192 
00193 static const char *read_ts(const char *buf, int *ts_start, int *ts_end,
00194                            int *x1, int *y1, int *x2, int *y2)
00195 {
00196     int i, hs, ms, ss, he, me, se;
00197 
00198     for (i=0; i<2; i++) {
00199         
00200         int c = sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
00201                        "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
00202                        &hs, &ms, &ss, ts_start, &he, &me, &se, ts_end,
00203                        x1, x2, y1, y2);
00204         buf += strcspn(buf, "\n") + 1;
00205         if (c >= 8) {
00206             *ts_start = 100*(ss + 60*(ms + 60*hs)) + *ts_start/10;
00207             *ts_end   = 100*(se + 60*(me + 60*he)) + *ts_end  /10;
00208             return buf;
00209         }
00210     }
00211     return NULL;
00212 }
00213 
00214 static int srt_decode_frame(AVCodecContext *avctx,
00215                             void *data, int *got_sub_ptr, AVPacket *avpkt)
00216 {
00217     AVSubtitle *sub = data;
00218     int ts_start, ts_end, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
00219     char buffer[2048];
00220     const char *ptr = avpkt->data;
00221     const char *end = avpkt->data + avpkt->size;
00222 
00223     if (avpkt->size <= 0)
00224         return avpkt->size;
00225 
00226     while (ptr < end && *ptr) {
00227         if (avctx->codec->id == CODEC_ID_SRT) {
00228             ptr = read_ts(ptr, &ts_start, &ts_end, &x1, &y1, &x2, &y2);
00229             if (!ptr)
00230                 break;
00231         } else {
00232             
00233             ts_start = av_rescale_q(avpkt->pts,
00234                                     avctx->time_base,
00235                                     (AVRational){1,100});
00236             ts_end   = av_rescale_q(avpkt->pts + avpkt->duration,
00237                                     avctx->time_base,
00238                                     (AVRational){1,100});
00239         }
00240         ptr = srt_to_ass(avctx, buffer, buffer+sizeof(buffer), ptr,
00241                          x1, y1, x2, y2);
00242         ff_ass_add_rect(sub, buffer, ts_start, ts_end-ts_start, 0);
00243     }
00244 
00245     *got_sub_ptr = sub->num_rects > 0;
00246     return avpkt->size;
00247 }
00248 
00249 #if CONFIG_SRT_DECODER
00250 AVCodec ff_srt_decoder = {
00251     .name         = "srt",
00252     .long_name    = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
00253     .type         = AVMEDIA_TYPE_SUBTITLE,
00254     .id           = AV_CODEC_ID_SRT,
00255     .init         = ff_ass_subtitle_header_default,
00256     .decode       = srt_decode_frame,
00257 };
00258 #endif
00259 
00260 #if CONFIG_SUBRIP_DECODER
00261 AVCodec ff_subrip_decoder = {
00262     .name         = "subrip",
00263     .long_name    = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
00264     .type         = AVMEDIA_TYPE_SUBTITLE,
00265     .id           = AV_CODEC_ID_SUBRIP,
00266     .init         = ff_ass_subtitle_header_default,
00267     .decode       = srt_decode_frame,
00268 };
00269 #endif