void init_vo_spudec(struct stream *stream, struct sh_video *sh_video, struct sh_sub *sh_sub) { unsigned width, height; spudec_free(vo_spudec); vo_spudec = NULL; // we currently can't work without video stream if (!sh_video) return; if (spudec_ifo) { unsigned int palette[16]; current_module = "spudec_init_vobsub"; if (vobsub_parse_ifo(NULL, spudec_ifo, palette, &width, &height, 1, -1, NULL) >= 0) vo_spudec = spudec_new_scaled(palette, width, height, NULL, 0); } width = sh_video->disp_w; height = sh_video->disp_h; #ifdef CONFIG_DVDREAD if (vo_spudec == NULL && stream->type == STREAMTYPE_DVD) { current_module = "spudec_init_dvdread"; vo_spudec = spudec_new_scaled(((dvd_priv_t *)(stream->priv))->cur_pgc->palette, width, height, NULL, 0); } #endif #ifdef CONFIG_DVDNAV if (vo_spudec == NULL && stream->type == STREAMTYPE_DVDNAV) { unsigned int *palette = mp_dvdnav_get_spu_clut(stream); current_module = "spudec_init_dvdnav"; vo_spudec = spudec_new_scaled(palette, width, height, NULL, 0); } #endif if (vo_spudec == NULL) { current_module = "spudec_init_normal"; vo_spudec = spudec_new_scaled(NULL, width, height, sh_sub ? sh_sub->extradata : NULL, sh_sub ? sh_sub->extradata_len : 0); spudec_set_font_factor(vo_spudec, font_factor); } if (vo_spudec) spudec_set_forced_subs_only(vo_spudec, forced_subs_only); }
static int init(struct sd *sd) { void *spudec = spudec_new_scaled(sd->sub_video_w, sd->sub_video_h, sd->extradata, sd->extradata_len); if (!spudec) return -1; struct sd_spu_priv *priv = talloc_zero(NULL, struct sd_spu_priv); priv->spudec = spudec; sd->priv = priv; return 0; }
/** * Decode a subtitle packet via libavcodec. * \return < 0 on error, > 0 if further processing is needed */ int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, double *pts, double *endpts) { AVCodecContext *ctx = sh->context; enum CodecID cid = CODEC_ID_NONE; int new_type = 0; int res; int got_sub; AVSubtitle sub; AVPacket pkt; switch (sh->type) { case 'b': cid = CODEC_ID_DVB_SUBTITLE; break; case 'p': cid = CODEC_ID_HDMV_PGS_SUBTITLE; break; case 'x': cid = CODEC_ID_XSUB; break; } av_init_packet(&pkt); pkt.data = *data; pkt.size = *size; pkt.pts = *pts * 1000; if (*pts != MP_NOPTS_VALUE && *endpts != MP_NOPTS_VALUE) pkt.convergence_duration = (*endpts - *pts) * 1000; if (!ctx) { AVCodec *sub_codec; init_avcodec(); ctx = avcodec_alloc_context3(NULL); sub_codec = avcodec_find_decoder(cid); if (!ctx || !sub_codec || avcodec_open2(ctx, sub_codec, NULL) < 0) { mp_msg(MSGT_SUBREADER, MSGL_FATAL, "Could not open subtitle decoder\n"); av_freep(&ctx); return -1; } sh->context = ctx; } res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt); if (res < 0) return res; if (*pts != MP_NOPTS_VALUE) { if (sub.end_display_time > sub.start_display_time) *endpts = *pts + sub.end_display_time / 1000.0; *pts += sub.start_display_time / 1000.0; } if (got_sub && vo_spudec && sub.num_rects == 0) spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, *pts, *endpts); if (got_sub && sub.num_rects > 0) { switch (sub.rects[0]->type) { case SUBTITLE_BITMAP: if (!vo_spudec) vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height, NULL, 0); spudec_set_paletted(vo_spudec, sub.rects[0]->pict.data[0], sub.rects[0]->pict.linesize[0], sub.rects[0]->pict.data[1], sub.rects[0]->x, sub.rects[0]->y, sub.rects[0]->w, sub.rects[0]->h, *pts, *endpts); vo_osd_changed(OSDTYPE_SPU); break; case SUBTITLE_TEXT: *data = strdup(sub.rects[0]->text); *size = strlen(*data); new_type = 't'; break; case SUBTITLE_ASS: *data = strdup(sub.rects[0]->ass); *size = strlen(*data); new_type = 'a'; break; } } if (got_sub) avsubtitle_free(&sub); return new_type; }
static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, int data_len, double pts, double duration) { struct sd_lavc_priv *priv = sh->context; AVCodecContext *ctx = priv->avctx; AVSubtitle sub; AVPacket pkt; clear(priv); av_init_packet(&pkt); pkt.data = data; pkt.size = data_len; pkt.pts = pts * 1000; if (duration >= 0) pkt.convergence_duration = duration * 1000; int got_sub; int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt); if (res < 0 || !got_sub) return; if (pts != MP_NOPTS_VALUE) { if (sub.end_display_time > sub.start_display_time) duration = (sub.end_display_time - sub.start_display_time) / 1000.0; pts += sub.start_display_time / 1000.0; } double endpts = MP_NOPTS_VALUE; if (pts != MP_NOPTS_VALUE && duration >= 0) endpts = pts + duration; if (vo_spudec && sub.num_rects == 0) spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, pts, endpts); if (sub.num_rects > 0) { switch (sub.rects[0]->type) { case SUBTITLE_BITMAP: // Assume resolution heuristics only work for PGS and DVB if (!osd->support_rgba || sh->type != 'p' && sh->type != 'b') { if (!vo_spudec) vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height, NULL, 0); old_avsub_to_spudec(sub.rects, sub.num_rects, pts, endpts); vo_osd_changed(OSDTYPE_SPU); break; } priv->inbitmaps = talloc_array(priv, struct sub_bitmap, sub.num_rects); for (int i = 0; i < sub.num_rects; i++) { struct AVSubtitleRect *r = sub.rects[i]; struct sub_bitmap *b = &priv->inbitmaps[i]; uint32_t *outbmp = talloc_size(priv->inbitmaps, r->w * r->h * 4); b->bitmap = outbmp; b->w = r->w; b->h = r->h; b->x = r->x; b->y = r->y; uint8_t *inbmp = r->pict.data[0]; uint32_t *palette = (uint32_t *) r->pict.data[1]; for (int y = 0; y < r->h; y++) { for (int x = 0; x < r->w; x++) *outbmp++ = palette[*inbmp++]; inbmp += r->pict.linesize[0] - r->w; }; } priv->count = sub.num_rects; priv->endpts = endpts; break; default: mp_msg(MSGT_SUBREADER, MSGL_ERR, "sd_lavc: unsupported subtitle " "type from libavcodec\n"); break; } } avsubtitle_free(&sub); }