00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00027 #include "ass.h"
00028 #include "libavutil/avstring.h"
00029 #include "libavutil/bprint.h"
00030 
00031 typedef struct {
00032     AVBPrint source;
00033     AVBPrint content;
00034     AVBPrint full;
00035 } SAMIContext;
00036 
00037 static int sami_paragraph_to_ass(AVCodecContext *avctx, const char *src)
00038 {
00039     SAMIContext *sami = avctx->priv_data;
00040     int ret = 0;
00041     char *tag = NULL;
00042     char *dupsrc = av_strdup(src);
00043     char *p = dupsrc;
00044 
00045     av_bprint_clear(&sami->content);
00046     for (;;) {
00047         char *saveptr = NULL;
00048         int prev_chr_is_space = 0;
00049         AVBPrint *dst = &sami->content;
00050 
00051         
00052         p = av_stristr(p, "<P");
00053         if (!p)
00054             break;
00055         if (p[2] != '>' && !isspace(p[2])) { 
00056             p++;
00057             continue;
00058         }
00059         if (dst->len) 
00060             av_bprintf(dst, "\\N");
00061         tag = av_strtok(p, ">", &saveptr);
00062         if (!tag || !saveptr)
00063             break;
00064         p = saveptr;
00065 
00066         
00067         if (av_stristr(tag, "ID=Source") || av_stristr(tag, "ID=\"Source\"")) {
00068             dst = &sami->source;
00069             av_bprint_clear(dst);
00070         }
00071 
00072         
00073         while (isspace(*p))
00074             p++;
00075         if (!strncmp(p, " ", 6)) {
00076             ret = -1;
00077             goto end;
00078         }
00079 
00080         
00081         while (*p) {
00082             if (*p == '<') {
00083                 if (!av_strncasecmp(p, "<P", 2) && (p[2] == '>' || isspace(p[2])))
00084                     break;
00085                 if (!av_strncasecmp(p, "<BR", 3))
00086                     av_bprintf(dst, "\\N");
00087                 p++;
00088                 while (*p && *p != '>')
00089                     p++;
00090                 if (!*p)
00091                     break;
00092                 if (*p == '>')
00093                     p++;
00094             }
00095             if (!isspace(*p))
00096                 av_bprint_chars(dst, *p, 1);
00097             else if (!prev_chr_is_space)
00098                 av_bprint_chars(dst, ' ', 1);
00099             prev_chr_is_space = isspace(*p);
00100             p++;
00101         }
00102     }
00103 
00104     av_bprint_clear(&sami->full);
00105     if (sami->source.len)
00106         av_bprintf(&sami->full, "{\\i1}%s{\\i0}\\N", sami->source.str);
00107     av_bprintf(&sami->full, "%s\r\n", sami->content.str);
00108 
00109 end:
00110     av_free(dupsrc);
00111     return ret;
00112 }
00113 
00114 static int sami_decode_frame(AVCodecContext *avctx,
00115                              void *data, int *got_sub_ptr, AVPacket *avpkt)
00116 {
00117     AVSubtitle *sub = data;
00118     const char *ptr = avpkt->data;
00119     SAMIContext *sami = avctx->priv_data;
00120 
00121     if (ptr && avpkt->size > 0 && !sami_paragraph_to_ass(avctx, ptr)) {
00122         int ts_start     = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
00123         int ts_duration  = avpkt->duration != -1 ?
00124                            av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
00125         ff_ass_add_rect(sub, sami->full.str, ts_start, ts_duration, 0);
00126     }
00127     *got_sub_ptr = sub->num_rects > 0;
00128     return avpkt->size;
00129 }
00130 
00131 static av_cold int sami_init(AVCodecContext *avctx)
00132 {
00133     SAMIContext *sami = avctx->priv_data;
00134     av_bprint_init(&sami->source,  0, 2048);
00135     av_bprint_init(&sami->content, 0, 2048);
00136     av_bprint_init(&sami->full,    0, 2048);
00137     return ff_ass_subtitle_header_default(avctx);
00138 }
00139 
00140 static av_cold int sami_close(AVCodecContext *avctx)
00141 {
00142     SAMIContext *sami = avctx->priv_data;
00143     av_bprint_finalize(&sami->source,  NULL);
00144     av_bprint_finalize(&sami->content, NULL);
00145     av_bprint_finalize(&sami->full,    NULL);
00146     return 0;
00147 }
00148 
00149 AVCodec ff_sami_decoder = {
00150     .name           = "sami",
00151     .long_name      = NULL_IF_CONFIG_SMALL("SAMI subtitle"),
00152     .type           = AVMEDIA_TYPE_SUBTITLE,
00153     .id             = AV_CODEC_ID_SAMI,
00154     .priv_data_size = sizeof(SAMIContext),
00155     .init           = sami_init,
00156     .close          = sami_close,
00157     .decode         = sami_decode_frame,
00158 };