static int init(struct sd *sd) { struct MPOpts *opts = sd->opts; if (!sd->ass_library || !sd->ass_renderer || !sd->ass_lock || !sd->codec) return -1; struct sd_ass_priv *ctx = talloc_zero(NULL, struct sd_ass_priv); sd->priv = ctx; ctx->extend_event = -1; ctx->is_converted = sd->converted_from != NULL; pthread_mutex_lock(sd->ass_lock); ctx->ass_track = ass_new_track(sd->ass_library); if (!ctx->is_converted) ctx->ass_track->track_type = TRACK_TYPE_ASS; ctx->shadow_track = ass_new_track(sd->ass_library); ctx->shadow_track->PlayResX = 384; ctx->shadow_track->PlayResY = 288; mp_ass_add_default_styles(ctx->shadow_track, opts); if (sd->extradata) { ass_process_codec_private(ctx->ass_track, sd->extradata, sd->extradata_len); } mp_ass_add_default_styles(ctx->ass_track, opts); pthread_mutex_unlock(sd->ass_lock); return 0; }
static int init(struct sd *sd) { struct MPOpts *opts = sd->opts; struct sd_ass_priv *ctx = talloc_zero(sd, struct sd_ass_priv); sd->priv = ctx; char *extradata = sd->codec->extradata; int extradata_size = sd->codec->extradata_size; if (strcmp(sd->codec->codec, "ass") != 0) { ctx->is_converted = true; ctx->converter = lavc_conv_create(sd->log, sd->codec->codec, extradata, extradata_size); if (!ctx->converter) return -1; extradata = lavc_conv_get_extradata(ctx->converter); extradata_size = extradata ? strlen(extradata) : 0; if (strcmp(sd->codec->codec, "eia_608") == 0) ctx->duration_unknown = 1; } ctx->ass_library = mp_ass_init(sd->global, sd->log); add_subtitle_fonts(sd); if (opts->ass_style_override) ass_set_style_overrides(ctx->ass_library, opts->ass_force_style_list); ctx->ass_track = ass_new_track(ctx->ass_library); if (!ctx->is_converted) ctx->ass_track->track_type = TRACK_TYPE_ASS; ctx->shadow_track = ass_new_track(ctx->ass_library); ctx->shadow_track->PlayResX = 384; ctx->shadow_track->PlayResY = 288; mp_ass_add_default_styles(ctx->shadow_track, opts); if (extradata) ass_process_codec_private(ctx->ass_track, extradata, extradata_size); mp_ass_add_default_styles(ctx->ass_track, opts); #if LIBASS_VERSION >= 0x01302000 ass_set_check_readorder(ctx->ass_track, sd->opts->sub_clear_on_seek ? 0 : 1); #endif ctx->frame_fps = sd->codec->frame_based; update_subtitle_speed(sd); enable_output(sd, true); ctx->packer = mp_ass_packer_alloc(ctx); return 0; }
ASS_Track* ass_default_track(ASS_Library* library) { ASS_Track* track = ass_new_track(library); track->track_type = TRACK_TYPE_ASS; track->Timer = 100.; track->PlayResY = 360; track->WrapStyle = 0; if (track->n_styles == 0) { // stupid hack to stop libass to add a default track // in front in ass_read_styles - this makes it impossible // to completely override the "Default" track. int sid = ass_alloc_style(track); init_style(track->styles + sid, "MPlayerDummy", track->PlayResY); } if (ass_styles_file) ass_read_styles(track, ass_styles_file, sub_cp); if (track->default_style <= 0) { int sid = ass_alloc_style(track); init_style(track->styles + sid, "Default", track->PlayResY); track->default_style = sid; if(fake_video) { track->PlayResX = 480; track->PlayResY = 270; } } ass_process_force_style(track); return track; }
ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts) { ASS_Track *track = ass_new_track(library); track->track_type = TRACK_TYPE_ASS; track->Timer = 100.; track->PlayResY = MP_ASS_FONT_PLAYRESY; track->WrapStyle = 0; if (opts->ass_styles_file && opts->ass_style_override) ass_read_styles(track, opts->ass_styles_file, sub_cp); if (track->n_styles == 0) { track->Kerning = true; int sid = ass_alloc_style(track); track->default_style = sid; ASS_Style *style = track->styles + sid; style->Name = strdup("Default"); style->Alignment = 2; mp_ass_set_style(style, opts->sub_text_style); } if (opts->ass_style_override) ass_process_force_style(track); return track; }
static csri_inst *libass_init_stream(csri_rend *renderer, const void *header, size_t headerlen, struct csri_openflag *flags) { csri_inst *rv; if (renderer != &csri_libass) return NULL; rv = (csri_inst *)malloc(sizeof(csri_inst)); if (!rv) return NULL; rv->ass_renderer = ass_renderer_init(renderer->ass_library); if (!rv->ass_renderer) { free(rv); return NULL; } ass_set_font_scale(rv->ass_renderer, 1.); ass_set_fonts(rv->ass_renderer, NULL, "Sans"); rv->ass_track = ass_new_track(csri_libass.ass_library); if (!rv->ass_track) { ass_renderer_done(rv->ass_renderer); free(rv); return NULL; } ass_process_codec_private(rv->ass_track, (void *)header, headerlen); return rv; }
static int init(struct sd *sd) { struct MPOpts *opts = sd->opts; if (!sd->ass_library || !sd->ass_renderer || !sd->codec) return -1; struct sd_ass_priv *ctx = talloc_zero(NULL, struct sd_ass_priv); sd->priv = ctx; ctx->is_converted = sd->converted_from != NULL; if (sd->ass_track) { ctx->ass_track = sd->ass_track; } else { ctx->ass_track = ass_new_track(sd->ass_library); if (!ctx->is_converted) ctx->ass_track->track_type = TRACK_TYPE_ASS; } if (sd->extradata) { ass_process_codec_private(ctx->ass_track, sd->extradata, sd->extradata_len); } mp_ass_add_default_styles(ctx->ass_track, opts); return 0; }
ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts) { ASS_Track *track = ass_new_track(library); track->track_type = TRACK_TYPE_ASS; track->Timer = 100.; mp_ass_add_default_styles(track, opts); return track; }
ASS_Track* ass_default_track(ASS_Library* library) { ASS_Track* track = ass_new_track(library); track->track_type = TRACK_TYPE_ASS; track->Timer = 100.; track->PlayResY = 288; track->WrapStyle = 0; if (ass_styles_file) ass_read_styles(track, ass_styles_file, sub_cp); if (track->n_styles == 0) { ASS_Style* style; int sid; double fs; uint32_t c1, c2; sid = ass_alloc_style(track); style = track->styles + sid; style->Name = strdup("Default"); style->FontName = (font_fontconfig >= 0 && sub_font_name) ? strdup(sub_font_name) : (font_fontconfig >= 0 && font_name) ? strdup(font_name) : strdup("Sans"); style->treat_fontname_as_pattern = 1; fs = track->PlayResY * text_font_scale_factor / 100.; // approximate autoscale coefficients if (subtitle_autoscale == 2) fs *= 1.3; else if (subtitle_autoscale == 3) fs *= 1.4; style->FontSize = fs; if (ass_color) c1 = strtoll(ass_color, NULL, 16); else c1 = 0xFFFF0000; if (ass_border_color) c2 = strtoll(ass_border_color, NULL, 16); else c2 = 0x00000000; style->PrimaryColour = c1; style->SecondaryColour = c1; style->OutlineColour = c2; style->BackColour = 0x00000000; style->BorderStyle = 1; style->Alignment = 2; style->Outline = 2; style->MarginL = 10; style->MarginR = 10; style->MarginV = 5; style->ScaleX = 1.; style->ScaleY = 1.; } ass_process_force_style(track); return track; }
/*Decode Header of SSA, needed to properly decode demux packets*/ bool CDVDSubtitlesLibass::DecodeHeader(char* data, int size) { CSingleLock lock(m_section); if(!m_library || !data) return false; if(!m_track) { CLog::Log(LOGINFO, "CDVDSubtitlesLibass: Creating new ASS track"); m_track = ass_new_track(m_library) ; } ass_process_codec_private(m_track, data, size); return true; }
/***************************************************************************** * Create: Open libass decoder. *****************************************************************************/ static int Create( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; ASS_Track *p_track; if( p_dec->fmt_in.i_codec != VLC_CODEC_SSA ) return VLC_EGENERIC; p_dec->pf_decode_sub = DecodeBlock; p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; /* */ p_sys->i_max_stop = VLC_TS_INVALID; p_sys->p_ass = AssHandleHold( p_dec ); if( !p_sys->p_ass ) { free( p_sys ); return VLC_EGENERIC; } vlc_mutex_init( &p_sys->lock ); p_sys->i_refcount = 1; /* Add a track */ vlc_mutex_lock( &libass_lock ); p_sys->p_track = p_track = ass_new_track( p_sys->p_ass->p_library ); if( !p_track ) { vlc_mutex_unlock( &libass_lock ); DecSysRelease( p_sys ); return VLC_EGENERIC; } ass_process_codec_private( p_track, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); vlc_mutex_unlock( &libass_lock ); p_dec->fmt_out.i_cat = SPU_ES; p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; return VLC_SUCCESS; }
void LibASS::initOSD() { if (osd_track && osd_style && osd_event && osd_renderer) return; osd_track = ass_new_track(ass); int styleID = ass_alloc_style(osd_track); osd_style = &osd_track->styles[styleID]; setOSDStyle(); int eventID = ass_alloc_event(osd_track); osd_event = &osd_track->events[eventID]; osd_event->Start = 0; osd_event->Duration = 1; osd_event->Style = styleID; osd_event->ReadOrder = eventID; osd_renderer = ass_renderer_init(ass); ass_set_fonts(osd_renderer, NULL, NULL, 1, NULL, 1); }
static void init(struct sh_sub *sh, struct osd_state *osd) { struct sd_ass_priv *ctx; if (sh->initialized) { ctx = sh->context; } else { ctx = talloc_zero(NULL, struct sd_ass_priv); sh->context = ctx; if (sh->type == 'a') { ctx->ass_track = ass_new_track(osd->ass_library); if (sh->extradata) ass_process_codec_private(ctx->ass_track, sh->extradata, sh->extradata_len); } else ctx->ass_track = mp_ass_default_track(osd->ass_library, sh->opts); } assert(osd->ass_track == NULL); osd->ass_track = ctx->ass_track; osd->vsfilter_aspect = sh->type == 'a'; osd->ass_track_changed = true; }
void LibASS::initASS(const QByteArray &ass_data) { if (ass_sub_track && ass_sub_renderer) return; ass_sub_track = ass_new_track(ass); if (!ass_data.isEmpty()) { ass_process_data(ass_sub_track, (char *)ass_data.data(), ass_data.size()); hasASSData = true; setASSStyle(); } else { ass_alloc_style(ass_sub_track); ass_sub_track->styles[0].ScaleX = ass_sub_track->styles[0].ScaleY = 1; overridePlayRes = true; hasASSData = false; setASSStyle(); } ass_sub_renderer = ass_renderer_init(ass); ass_set_fonts(ass_sub_renderer, NULL, NULL, true, NULL, true); }
static av_cold int init_subtitles(AVFilterContext *ctx) { int j, ret, sid; int k = 0; AVDictionary *codec_opts = NULL; AVFormatContext *fmt = NULL; AVCodecContext *dec_ctx = NULL; AVCodec *dec = NULL; const AVCodecDescriptor *dec_desc; AVStream *st; AVPacket pkt; AssContext *ass = ctx->priv; /* Init libass */ ret = init(ctx); if (ret < 0) return ret; ass->track = ass_new_track(ass->library); if (!ass->track) { av_log(ctx, AV_LOG_ERROR, "Could not create a libass track\n"); return AVERROR(EINVAL); } /* Open subtitles file */ ret = avformat_open_input(&fmt, ass->filename, NULL, NULL); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Unable to open %s\n", ass->filename); goto end; } ret = avformat_find_stream_info(fmt, NULL); if (ret < 0) goto end; /* Locate subtitles stream */ if (ass->stream_index < 0) ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0); else { ret = -1; if (ass->stream_index < fmt->nb_streams) { for (j = 0; j < fmt->nb_streams; j++) { if (fmt->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { if (ass->stream_index == k) { ret = j; break; } k++; } } } } if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Unable to locate subtitle stream in %s\n", ass->filename); goto end; } sid = ret; st = fmt->streams[sid]; /* Load attached fonts */ for (j = 0; j < fmt->nb_streams; j++) { AVStream *st = fmt->streams[j]; if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT && attachment_is_font(st)) { const AVDictionaryEntry *tag = NULL; tag = av_dict_get(st->metadata, "filename", NULL, AV_DICT_MATCH_CASE); if (tag) { av_log(ctx, AV_LOG_DEBUG, "Loading attached font: %s\n", tag->value); ass_add_font(ass->library, tag->value, st->codecpar->extradata, st->codecpar->extradata_size); } else { av_log(ctx, AV_LOG_WARNING, "Font attachment has no filename, ignored.\n"); } } } /* Initialize fonts */ ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1); /* Open decoder */ dec = avcodec_find_decoder(st->codecpar->codec_id); if (!dec) { av_log(ctx, AV_LOG_ERROR, "Failed to find subtitle codec %s\n", avcodec_get_name(st->codecpar->codec_id)); return AVERROR(EINVAL); } dec_desc = avcodec_descriptor_get(st->codecpar->codec_id); if (dec_desc && !(dec_desc->props & AV_CODEC_PROP_TEXT_SUB)) { av_log(ctx, AV_LOG_ERROR, "Only text based subtitles are currently supported\n"); return AVERROR_PATCHWELCOME; } if (ass->charenc) av_dict_set(&codec_opts, "sub_charenc", ass->charenc, 0); if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,26,100)) av_dict_set(&codec_opts, "sub_text_format", "ass", 0); dec_ctx = avcodec_alloc_context3(dec); if (!dec_ctx) return AVERROR(ENOMEM); ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); if (ret < 0) goto end; /* * This is required by the decoding process in order to rescale the * timestamps: in the current API the decoded subtitles have their pts * expressed in AV_TIME_BASE, and thus the lavc internals need to know the * stream time base in order to achieve the rescaling. * * That API is old and needs to be reworked to match behaviour with A/V. */ av_codec_set_pkt_timebase(dec_ctx, st->time_base); ret = avcodec_open2(dec_ctx, NULL, &codec_opts); if (ret < 0) goto end; if (ass->force_style) { char **list = NULL; char *temp = NULL; char *ptr = av_strtok(ass->force_style, ",", &temp); int i = 0; while (ptr) { av_dynarray_add(&list, &i, ptr); if (!list) { ret = AVERROR(ENOMEM); goto end; } ptr = av_strtok(NULL, ",", &temp); } av_dynarray_add(&list, &i, NULL); if (!list) { ret = AVERROR(ENOMEM); goto end; } ass_set_style_overrides(ass->library, list); av_free(list); } /* Decode subtitles and push them into the renderer (libass) */ if (dec_ctx->subtitle_header) ass_process_codec_private(ass->track, dec_ctx->subtitle_header, dec_ctx->subtitle_header_size); av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; while (av_read_frame(fmt, &pkt) >= 0) { int i, got_subtitle; AVSubtitle sub = {0}; if (pkt.stream_index == sid) { ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt); if (ret < 0) { av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n", av_err2str(ret)); } else if (got_subtitle) { const int64_t start_time = av_rescale_q(sub.pts, AV_TIME_BASE_Q, av_make_q(1, 1000)); const int64_t duration = sub.end_display_time; for (i = 0; i < sub.num_rects; i++) { char *ass_line = sub.rects[i]->ass; if (!ass_line) break; if (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57,25,100)) ass_process_data(ass->track, ass_line, strlen(ass_line)); else ass_process_chunk(ass->track, ass_line, strlen(ass_line), start_time, duration); } } } av_packet_unref(&pkt); avsubtitle_free(&sub); } end: av_dict_free(&codec_opts); avcodec_close(dec_ctx); avcodec_free_context(&dec_ctx); avformat_close_input(&fmt); return ret; }
ASS_Track *mp_ass_default_track(ASS_Library *library) { ASS_Track *track = ass_new_track(library); track->track_type = TRACK_TYPE_ASS; track->Timer = 100.; track->PlayResY = 288; track->WrapStyle = 0; if (ass_styles_file) ass_read_styles(track, ass_styles_file, sub_cp); if (track->n_styles == 0) { track->Kerning = true; int sid = ass_alloc_style(track); ASS_Style *style = track->styles + sid; style->Name = strdup("Default"); style->FontName = (font_fontconfig >= 0 && sub_font_name) ? strdup(sub_font_name) : (font_fontconfig >= 0 && font_name) ? strdup(font_name) : strdup("Sans"); style->treat_fontname_as_pattern = 1; double fs = track->PlayResY * text_font_scale_factor / 100.; /* The font size is always proportional to video height only; * real -subfont-autoscale behavior is not implemented. * Apply a correction that corresponds to about 4:3 aspect ratio * video to get a size somewhat closer to what non-libass rendering * would produce with the same text_font_scale_factor * and subtitle_autoscale. */ if (subtitle_autoscale == 2) fs *= 1.3; else if (subtitle_autoscale == 3) fs *= 1.7; uint32_t c1 = 0xFFFFFF00; uint32_t c2 = 0x00000000; if (ass_color) c1 = strtoll(ass_color, NULL, 16); if (ass_border_color) c2 = strtoll(ass_border_color, NULL, 16); style->FontSize = fs; style->PrimaryColour = c1; style->SecondaryColour = c1; style->OutlineColour = c2; style->BackColour = 0x00000000; style->BorderStyle = 1; style->Alignment = 2; style->Outline = fs / 16; style->MarginL = 10; style->MarginR = 10; style->MarginV = 5; style->ScaleX = 1.; style->ScaleY = 1.; } ass_process_force_style(track); return track; }
/***************************************************************************** * Create: Open libass decoder. *****************************************************************************/ static int Create( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_SSA ) return VLC_EGENERIC; p_dec->pf_decode_sub = DecodeBlock; p_dec->pf_flush = Flush; p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; /* */ vlc_mutex_init( &p_sys->lock ); p_sys->i_refcount = 1; memset( &p_sys->fmt, 0, sizeof(p_sys->fmt) ); p_sys->i_max_stop = VLC_TS_INVALID; p_sys->p_library = NULL; p_sys->p_renderer = NULL; p_sys->p_track = NULL; /* Create libass library */ ASS_Library *p_library = p_sys->p_library = ass_library_init(); if( !p_library ) { msg_Warn( p_dec, "Libass library creation failed" ); DecSysRelease( p_sys ); return VLC_EGENERIC; } /* load attachments */ input_attachment_t **pp_attachments; int i_attachments; if( decoder_GetInputAttachments( p_dec, &pp_attachments, &i_attachments )) { i_attachments = 0; pp_attachments = NULL; } for( int k = 0; k < i_attachments; k++ ) { input_attachment_t *p_attach = pp_attachments[k]; bool found = false; /* Check mimetype*/ if( !strcasecmp( p_attach->psz_mime, "application/x-truetype-font" ) ) found = true; /* Then extension */ else if( !found && strlen( p_attach->psz_name ) > 4 ) { char *ext = p_attach->psz_name + strlen( p_attach->psz_name ) - 4; if( !strcasecmp( ext, ".ttf" ) || !strcasecmp( ext, ".otf" ) || !strcasecmp( ext, ".ttc" ) ) found = true; } if( found ) { msg_Dbg( p_dec, "adding embedded font %s", p_attach->psz_name ); ass_add_font( p_sys->p_library, p_attach->psz_name, p_attach->p_data, p_attach->i_data ); } vlc_input_attachment_Delete( p_attach ); } free( pp_attachments ); ass_set_extract_fonts( p_library, true ); ass_set_style_overrides( p_library, NULL ); /* Create the renderer */ ASS_Renderer *p_renderer = p_sys->p_renderer = ass_renderer_init( p_library ); if( !p_renderer ) { msg_Warn( p_dec, "Libass renderer creation failed" ); DecSysRelease( p_sys ); return VLC_EGENERIC; } ass_set_use_margins( p_renderer, false); //if( false ) // ass_set_margins( p_renderer, int t, int b, int l, int r); ass_set_hinting( p_renderer, ASS_HINTING_LIGHT ); ass_set_font_scale( p_renderer, 1.0 ); ass_set_line_spacing( p_renderer, 0.0 ); #if defined( __ANDROID__ ) const char *psz_font = "/system/fonts/DroidSans-Bold.ttf"; const char *psz_family = "Droid Sans Bold"; #elif defined( __APPLE__ ) const char *psz_font = NULL; /* We don't ship a default font with VLC */ const char *psz_family = "Helvetica Neue"; /* Use HN if we can't find anything more suitable - Arial is not on all Apple platforms */ #else const char *psz_font = NULL; /* We don't ship a default font with VLC */ const char *psz_family = "Arial"; /* Use Arial if we can't find anything more suitable */ #endif #ifdef HAVE_FONTCONFIG #if defined(_WIN32) dialog_progress_bar_t *p_dialog = dialog_ProgressCreate( p_dec, _("Building font cache"), _( "Please wait while your font cache is rebuilt.\n" "This should take less than a minute." ), NULL ); #endif ass_set_fonts( p_renderer, psz_font, psz_family, 1, NULL, 1 ); // setup default font/family #if defined(_WIN32) if( p_dialog ) { dialog_ProgressSet( p_dialog, NULL, 1.0 ); dialog_ProgressDestroy( p_dialog ); } #endif #else ass_set_fonts( p_renderer, psz_font, psz_family, 1, NULL, 1 ); #endif /* Add a track */ ASS_Track *p_track = p_sys->p_track = ass_new_track( p_sys->p_library ); if( !p_track ) { DecSysRelease( p_sys ); return VLC_EGENERIC; } ass_process_codec_private( p_track, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); p_dec->fmt_out.i_cat = SPU_ES; p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; return VLC_SUCCESS; }
static void VS_CC assInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi) { AssData *d = (AssData *) * instanceData; vsapi->setVideoInfo(d->vi, 2, node); d->ass_library = ass_library_init(); if(!d->ass_library) { vsapi->setError(out, "failed to initialize ASS library"); return; } ass_set_message_cb(d->ass_library, assDebugCallback, (void *)d->debuglevel); ass_set_extract_fonts(d->ass_library, 0); ass_set_style_overrides(d->ass_library, 0); d->ass_renderer = ass_renderer_init(d->ass_library); if(!d->ass_renderer) { vsapi->setError(out, "failed to initialize ASS renderer"); return; } ass_set_font_scale(d->ass_renderer, d->scale); ass_set_frame_size(d->ass_renderer, d->vi[0].width, d->vi[0].height); ass_set_margins(d->ass_renderer, d->margins[0], d->margins[1], d->margins[2], d->margins[3]); ass_set_use_margins(d->ass_renderer, 1); if(d->linespacing) ass_set_line_spacing(d->ass_renderer, d->linespacing); if(d->sar) { ass_set_aspect_ratio(d->ass_renderer, (double)d->vi[0].width / d->vi[0].height * d->sar, 1); } if(d->fontdir) ass_set_fonts_dir(d->ass_library, d->fontdir); ass_set_fonts(d->ass_renderer, NULL, NULL, 1, NULL, 1); if(d->file == NULL) { char *str, *text, x[16], y[16]; size_t siz; const char *fmt = "[Script Info]\n" "ScriptType: v4.00+\n" "PlayResX: %s\n" "PlayResY: %s\n" "[V4+ Styles]\n" "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n" "Style: Default,%s\n" "[Events]\n" "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n" "Dialogue: 0,0:00:00.00,0:00:10.00,Default,,0,0,0,,%s\n"; sprintf(x, "%d", d->vi[0].width); sprintf(y, "%d", d->vi[0].height); text = strrepl(d->text, "\n", "\\N"); siz = (strlen(fmt) + strlen(x) + strlen(y) + strlen(d->style) + strlen(text)) * sizeof(char); str = malloc(siz); sprintf(str, fmt, x, y, d->style, text); free(text); d->ass = ass_new_track(d->ass_library); ass_process_data(d->ass, str, strlen(str)); free(str); } else { d->ass = ass_read_file(d->ass_library, (char *)d->file, (char *)d->charset); } if(!d->ass) { vsapi->setError(out, "unable to parse input file"); return; } }
/***************************************************************************** * Create: Open libass decoder. *****************************************************************************/ static int Create( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_SSA ) return VLC_EGENERIC; p_dec->pf_decode_sub = DecodeBlock; p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; /* */ vlc_mutex_init( &p_sys->lock ); p_sys->i_refcount = 1; memset( &p_sys->fmt, 0, sizeof(p_sys->fmt) ); p_sys->i_max_stop = VLC_TS_INVALID; p_sys->p_library = NULL; p_sys->p_renderer = NULL; p_sys->p_track = NULL; /* Create libass library */ ASS_Library *p_library = p_sys->p_library = ass_library_init(); if( !p_library ) { msg_Warn( p_dec, "Libass library creation failed" ); DecSysRelease( p_sys ); return VLC_EGENERIC; } /* load attachments */ input_attachment_t **pp_attachments; int i_attachments; if( decoder_GetInputAttachments( p_dec, &pp_attachments, &i_attachments )) { i_attachments = 0; pp_attachments = NULL; } for( int k = 0; k < i_attachments; k++ ) { input_attachment_t *p_attach = pp_attachments[k]; if( !strcasecmp( p_attach->psz_mime, "application/x-truetype-font" ) ) { msg_Dbg( p_dec, "adding embedded font %s", p_attach->psz_name ); ass_add_font( p_sys->p_library, p_attach->psz_name, p_attach->p_data, p_attach->i_data ); } vlc_input_attachment_Delete( p_attach ); } free( pp_attachments ); ass_set_extract_fonts( p_library, true ); ass_set_style_overrides( p_library, NULL ); /* Create the renderer */ ASS_Renderer *p_renderer = p_sys->p_renderer = ass_renderer_init( p_library ); if( !p_renderer ) { msg_Warn( p_dec, "Libass renderer creation failed" ); DecSysRelease( p_sys ); return VLC_EGENERIC; } ass_set_use_margins( p_renderer, false); //if( false ) // ass_set_margins( p_renderer, int t, int b, int l, int r); ass_set_hinting( p_renderer, ASS_HINTING_LIGHT ); ass_set_font_scale( p_renderer, 1.0 ); ass_set_line_spacing( p_renderer, 0.0 ); const char *psz_font = NULL; /* We don't ship a default font with VLC */ const char *psz_family = "Arial"; /* Use Arial if we can't find anything more suitable */ #ifdef ANDROID /* is this useful? */ ass_set_fonts_dir( p_library, "/system/fonts" ); /* don't crash libass */ psz_font = "/system/fonts/DroidSansFallback.ttf"; #endif #ifdef HAVE_FONTCONFIG #if defined(WIN32) dialog_progress_bar_t *p_dialog = dialog_ProgressCreate( p_dec, _("Building font cache"), _( "Please wait while your font cache is rebuilt.\n" "This should take less than a minute." ), NULL ); if( p_dialog ) dialog_ProgressSet( p_dialog, NULL, 0.2 ); #endif ass_set_fonts( p_renderer, psz_font, psz_family, true, NULL, 1 ); // setup default font/family #ifdef WIN32 if( p_dialog ) { dialog_ProgressSet( p_dialog, NULL, 1.0 ); dialog_ProgressDestroy( p_dialog ); } #endif #else /* FIXME you HAVE to give him a font if no fontconfig */ ass_set_fonts( p_renderer, psz_font, psz_family, false, NULL, 1 ); #endif /* Add a track */ ASS_Track *p_track = p_sys->p_track = ass_new_track( p_sys->p_library ); if( !p_track ) { DecSysRelease( p_sys ); return VLC_EGENERIC; } ass_process_codec_private( p_track, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); p_dec->fmt_out.i_cat = SPU_ES; p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; return VLC_SUCCESS; }
static void *ass_reader_thread(void *) { set_threadname("ass_reader_thread"); while (!sem_wait(&ass_sem)) { if (!ass_reader_running) break; ass_data *a = (ass_data *) ass_queue.pop(); if (!a) { if (!ass_reader_running) break; continue; } OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(ass_mutex); std::map<int,ASS_Track*>::iterator it = ass_map.find(a->pid); ASS_Track *track; if (it == ass_map.end()) { CFrameBuffer *fb = CFrameBuffer::getInstance(); int xres = fb->getScreenWidth(true); int yres = fb->getScreenHeight(true); if (!ass_library) { ass_library = ass_library_init(); ass_set_extract_fonts(ass_library, 1); ass_set_style_overrides(ass_library, NULL); ass_renderer = ass_renderer_init(ass_library); ass_set_frame_size(ass_renderer, xres, yres); ass_set_margins(ass_renderer, 3 * yres / 100, 3 * yres / 100, 3 * xres / 100, 3 * xres / 100); ass_set_use_margins(ass_renderer, 1); ass_set_hinting(ass_renderer, ASS_HINTING_LIGHT); ass_set_aspect_ratio(ass_renderer, 1.0, 1.0); ass_font = *sub_font_file; ass_set_fonts(ass_renderer, ass_font.c_str(), "Arial", 0, NULL, 1); } track = ass_new_track(ass_library); track->PlayResX = xres; track->PlayResY = yres; ass_size = sub_font_size; ass_set_font_scale(ass_renderer, ((double) ass_size)/ASS_CUSTOM_FONT_SIZE); if (a->c->subtitle_header) { std::string ass_hdr = ass_subtitle_header_default(); if (ass_hdr.compare((char*) a->c->subtitle_header)) { ass_process_codec_private(track, (char *) a->c->subtitle_header, a->c->subtitle_header_size); } else { // This is the FFMPEG default ASS header. Use something more suitable instead: ass_hdr = ass_subtitle_header_custom(); ass_process_codec_private(track, (char *) ass_hdr.c_str(), ass_hdr.length()); } } ass_map[a->pid] = track; if (a->pid == dvbsub_pid) ass_track = track; //fprintf(stderr, "### got subtitle track %d, subtitle header: \n---\n%s\n---\n", pid, c->subtitle_header); } else track = it->second; for (unsigned int i = 0; i < a->sub.num_rects; i++) if (a->sub.rects[i]->ass) ass_process_data(track, a->sub.rects[i]->ass, strlen(a->sub.rects[i]->ass)); avsubtitle_free(&a->sub); delete a; } ass_reader_running = false; pthread_exit(NULL); }
/***************************************************************************** * Create: Open libass decoder. *****************************************************************************/ static int Create( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_SSA ) return VLC_EGENERIC; p_dec->pf_decode_sub = DecodeBlock; p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; /* */ vlc_mutex_init( &p_sys->lock ); p_sys->i_refcount = 1; memset( &p_sys->fmt, 0, sizeof(p_sys->fmt) ); p_sys->i_max_stop = VLC_TS_INVALID; p_sys->p_library = NULL; p_sys->p_renderer = NULL; p_sys->p_track = NULL; /* Create libass library */ ASS_Library *p_library = p_sys->p_library = ass_library_init(); if( !p_library ) { msg_Warn( p_dec, "Libass library creation failed" ); DecSysRelease( p_sys ); return VLC_EGENERIC; } /* load attachments */ input_attachment_t **pp_attachments; int i_attachments; if( decoder_GetInputAttachments( p_dec, &pp_attachments, &i_attachments )) { i_attachments = 0; pp_attachments = NULL; } for( int k = 0; k < i_attachments; k++ ) { input_attachment_t *p_attach = pp_attachments[k]; bool found = false; /* Check mimetype*/ if( !strcasecmp( p_attach->psz_mime, "application/x-truetype-font" ) ) found = true; /* Then extension */ else if( !found && strlen( p_attach->psz_name ) > 4 ) { char *ext = p_attach->psz_name + strlen( p_attach->psz_name ) - 4; if( !strcasecmp( ext, ".ttf" ) || !strcasecmp( ext, ".otf" ) || !strcasecmp( ext, ".ttc" ) ) found = true; } if( found ) { msg_Dbg( p_dec, "adding embedded font %s", p_attach->psz_name ); ass_add_font( p_sys->p_library, p_attach->psz_name, p_attach->p_data, p_attach->i_data ); } vlc_input_attachment_Delete( p_attach ); } free( pp_attachments ); ass_set_extract_fonts( p_library, true ); ass_set_style_overrides( p_library, NULL ); /* Create the renderer */ ASS_Renderer *p_renderer = p_sys->p_renderer = ass_renderer_init( p_library ); if( !p_renderer ) { msg_Warn( p_dec, "Libass renderer creation failed" ); DecSysRelease( p_sys ); return VLC_EGENERIC; } ass_set_use_margins( p_renderer, false); //if( false ) // ass_set_margins( p_renderer, int t, int b, int l, int r); ass_set_hinting( p_renderer, ASS_HINTING_LIGHT ); ass_set_font_scale( p_renderer, 1.0 ); ass_set_line_spacing( p_renderer, 0.0 ); #if defined( __ANDROID__ ) const char *psz_font = "/system/fonts/DroidSans-Bold.ttf"; const char *psz_family = "Droid Sans Bold"; #elif defined (__APPLE__) #if !TARGET_OS_IPHONE const char *psz_font = NULL; /* We don't ship a default font with VLC */ const char *psz_family = "Arial"; /* Use Arial if we can't find anything more suitable */ #else CFURLRef fileURL; fileURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("OpenSans-Regular.ttf"), NULL, NULL); if (!fileURL) return VLC_EGENERIC; CFStringRef urlString = CFURLCopyFileSystemPath(fileURL, kCFURLPOSIXPathStyle); CFRelease(fileURL); if (!urlString) return VLC_EGENERIC; CFIndex length = CFStringGetLength(urlString); if (!length) return VLC_EGENERIC; length++; char *psz_path = (char *)malloc(length); CFStringGetCString(urlString, psz_path, length, kCFStringEncodingUTF8); CFRelease(urlString); const char *psz_font = (const char *)strdup(psz_path); free(psz_path); const char *psz_family = "Open Sans"; #endif #else const char *psz_font = NULL; /* We don't ship a default font with VLC */ const char *psz_family = "Arial"; /* Use Arial if we can't find anything more suitable */ #endif #ifdef HAVE_FONTCONFIG #if defined(_WIN32) || defined(__APPLE__) dialog_progress_bar_t *p_dialog = dialog_ProgressCreate( p_dec, _("Building font cache"), _( "Please wait while your font cache is rebuilt.\n" "This should take less than a minute." ), NULL ); #endif ass_set_fonts( p_renderer, psz_font, psz_family, true, NULL, 1 ); // setup default font/family #if defined(_WIN32) || defined(__APPLE__) if( p_dialog ) { dialog_ProgressSet( p_dialog, NULL, 1.0 ); dialog_ProgressDestroy( p_dialog ); } #endif #else /* FIXME you HAVE to give him a font if no fontconfig */ ass_set_fonts( p_renderer, psz_font, psz_family, false, NULL, 1 ); #endif /* Add a track */ ASS_Track *p_track = p_sys->p_track = ass_new_track( p_sys->p_library ); if( !p_track ) { DecSysRelease( p_sys ); return VLC_EGENERIC; } ass_process_codec_private( p_track, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); p_dec->fmt_out.i_cat = SPU_ES; p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; return VLC_SUCCESS; }