[MPlayer-dev-eng] [PATCH] Support for DVB subtitles
Nicolas George
nicolas.george at normalesup.org
Sat Feb 28 00:41:53 CET 2009
Hi.
The attached patch adds support for DVB subtitles. The color is currently
downgraded to a single alpha channel; there is room for enhancement here.
If anyone thinks that the way I plugged it directly in vf_ass, my answer is
that I totally agree and I would like some help to have my previous patch
accepted.
Regards,
--
Nicolas George
-------------- next part --------------
Makefile | 1 +
command.c | 4 +
dvbsub.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++
dvbsub.h | 17 ++++
libmpcodecs/vf_ass.c | 12 ++-
libmpdemux/demux_lavf.c | 6 ++
mp_msg.h | 2 +
mpcommon.c | 6 +-
8 files changed, 251 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
index 449b058..67e8315 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,7 @@ LDFLAGS_MENCODER = $(EXTRALIBS_MENCODER) \
SRCS_COMMON = asxparser.c \
codec-cfg.c \
cpudetect.c \
+ dvbsub.c \
edl.c \
find_sub.c \
fmt-conversion.c \
diff --git a/command.c b/command.c
index 0a67038..02c941f 100644
--- a/command.c
+++ b/command.c
@@ -27,6 +27,7 @@
#include "libmpcodecs/dec_video.h"
#include "vobsub.h"
#include "spudec.h"
+#include "dvbsub.h"
#include "get_path.h"
#ifdef CONFIG_TV
#include "stream/tv.h"
@@ -1455,6 +1456,7 @@ static int mp_property_sub(m_option_t * prop, int action, void *arg,
#ifdef CONFIG_ASS
ass_track = 0;
#endif
+ dvbsub_reset();
if (source == SUB_SOURCE_VOBSUB) {
vobsub_id = vobsub_get_id_by_index(vo_vobsub, mpctx->global_sub_pos - mpctx->global_sub_indices[SUB_SOURCE_VOBSUB]);
@@ -1491,6 +1493,8 @@ static int mp_property_sub(m_option_t * prop, int action, void *arg,
sh_sub_t *sh = d_sub->sh;
if (sh->type == 'v')
init_vo_spudec();
+ else if(sh->type == 'b')
+ dvbsub_init(sh->extradata, sh->extradata_len);
#ifdef CONFIG_ASS
else if (ass_enabled)
ass_track = sh->ass_track;
diff --git a/dvbsub.c b/dvbsub.c
new file mode 100644
index 0000000..c5fcd3e
--- /dev/null
+++ b/dvbsub.c
@@ -0,0 +1,208 @@
+#include "mplayer.h"
+#include "mp_msg.h"
+#include "libavcodec/avcodec.h"
+#include "dvbsub.h"
+
+struct dvbsus_frame {
+ dvbsub_frame_t *next;
+ AVSubtitleRect **rect;
+ float start, end;
+ int n_rect;
+};
+
+static AVCodecContext *decoder = NULL;
+dvbsub_frame_t *dvbsub_frames = NULL;
+static ass_image_t *images = NULL;
+static int rendered = 0;
+static int frame_w = 360;
+static int frame_h = 576;
+
+static void dvbsub_invalidate_images(void)
+{
+ ass_image_t *ni;
+
+ rendered = 0;
+ while (images) {
+ ni = images->next;
+ free(images->bitmap);
+ free(images);
+ images = ni;
+ }
+}
+
+void dvbsub_configure(int w, int h)
+{
+ dvbsub_invalidate_images();
+ frame_w = w;
+ frame_h = h;
+}
+
+static void dvbsub_free_frame(dvbsub_frame_t *frame)
+{
+ int i;
+
+ for (i = 0; i < frame->n_rect; i++) {
+ av_free(frame->rect[i]->pict.data[0]);
+ av_free(frame->rect[i]->pict.data[1]);
+ av_free(frame->rect[i]);
+ }
+ av_free(frame->rect);
+ av_free(frame);
+ dvbsub_invalidate_images();
+}
+
+void dvbsub_reset(void)
+{
+ dvbsub_frame_t *nf;
+
+ while (dvbsub_frames) {
+ nf = dvbsub_frames->next;
+ dvbsub_free_frame(dvbsub_frames);
+ dvbsub_frames = nf;
+ }
+ dvbsub_invalidate_images();
+ if (decoder) {
+ avcodec_close(decoder);
+ av_freep(&decoder);
+ }
+}
+
+void dvbsub_init(void *extradata, int extradata_size)
+{
+ int r;
+ AVCodec *codec;
+
+ dvbsub_reset();
+ decoder = avcodec_alloc_context();
+ codec = avcodec_find_decoder(CODEC_ID_DVB_SUBTITLE);
+ if (codec == NULL) {
+ mp_msg(MSGT_DVBSUB, MSGL_ERR, "dvbsub decoder not found\n");
+ return;
+ }
+ if (extradata_size == sizeof(int))
+ decoder->sub_id = *(int *)extradata;
+ r = avcodec_open(decoder, codec);
+ if (r < 0) {
+ mp_msg(MSGT_DVBSUB, MSGL_ERR, "dvbsub decoder not opened\n");
+ av_freep(&decoder);
+ return;
+ }
+}
+
+static void dvbsub_add_frame(double start, double end, AVSubtitleRect **rect,
+ int n_rect)
+{
+ dvbsub_frame_t *frame, *f, **prev, *nf;
+
+ frame = malloc(sizeof(dvbsub_frame_t));
+ if (frame == NULL)
+ return;
+ frame->start = start;
+ frame->end = end;
+ frame->rect = rect;
+ frame->n_rect = n_rect;
+
+ f = dvbsub_frames;
+ prev = &dvbsub_frames;
+ for (f = dvbsub_frames; f; f = f->next) {
+ if (f->start >= start)
+ break;
+ if (f->end >= start)
+ f->end = start;
+ prev = &f->next;
+ }
+ *prev = frame;
+ frame->next = NULL;
+ while (f) {
+ nf = f->next;
+ dvbsub_free_frame(f);
+ f = nf;
+ }
+ dvbsub_invalidate_images();
+}
+
+void dvbsub_process_packet(uint8_t *packet, int size, double pts)
+{
+ int r, got_sub = 0;
+ AVSubtitle sub;
+
+ if (!decoder)
+ return;
+ r = avcodec_decode_subtitle(decoder, &sub, &got_sub, packet, size);
+ if (!got_sub)
+ return;
+ if (sub.format != 0)
+ return;
+ dvbsub_add_frame(pts + sub.start_display_time / 1000.0,
+ pts + sub.end_display_time / 1000.0, sub.rects, sub.num_rects);
+}
+
+ass_image_t *dvbsub_render_frame(double pts)
+{
+ dvbsub_frame_t *nf;
+ ass_image_t *ni, **tail;
+ int i, psize, x, y, w, h, dx, dy, stride;
+ uint8_t (*palette)[4];
+ uint8_t *src, *dst;
+
+ pts += sub_delay;
+ while (dvbsub_frames && dvbsub_frames->end < pts) {
+ nf = dvbsub_frames->next;
+ dvbsub_free_frame(dvbsub_frames);
+ dvbsub_frames = nf;
+ }
+ if (rendered)
+ return images;
+ tail = &images;
+ if (dvbsub_frames) {
+ for (i = 0; i < dvbsub_frames->n_rect; i++) {
+ palette = (uint8_t (*)[4])dvbsub_frames->rect[i]->pict.data[1];
+ psize = dvbsub_frames->rect[i]->nb_colors;
+ x = dvbsub_frames->rect[i]->x;
+ y = dvbsub_frames->rect[i]->y;
+ w = dvbsub_frames->rect[i]->w;
+ h = dvbsub_frames->rect[i]->h;
+ dx = 0;
+ dy = 0;
+ if (x < 0) {
+ w += x;
+ dx -= x;
+ x = 0;
+ }
+ if (x + w > frame_w)
+ w = frame_w - x;
+ if (y < 0) {
+ h -= y;
+ dy -= y;
+ y = 0;
+ }
+ if (y + h > frame_h)
+ h = frame_h - y;
+ if (w < 0 || h < 0)
+ continue;
+ stride = dvbsub_frames->rect[i]->pict.linesize[0];
+ src = dvbsub_frames->rect[i]->pict.data[0] + dx + dy * stride;
+ ni = malloc(sizeof(ass_image_t));
+ ni->w = w;
+ ni->h = h;
+ ni->dst_x = x;
+ ni->dst_y = y;
+ ni->stride = w;
+ ni->bitmap = malloc(w * h);
+ dst = ni->bitmap;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++)
+ *(dst++) = palette[*(src++)][3];
+ src += stride - w;
+ }
+ ni->color = palette[psize - 1][0] * 0x100 +
+ palette[psize - 1][1] * 0x10000 +
+ palette[psize - 1][2] * 0x1000000;
+ *tail = ni;
+ tail = &ni->next;
+ }
+ }
+ *tail = NULL;
+ rendered = 1;
+ return images;
+}
diff --git a/dvbsub.h b/dvbsub.h
new file mode 100644
index 0000000..7049904
--- /dev/null
+++ b/dvbsub.h
@@ -0,0 +1,17 @@
+#ifndef MPLAYER_DVBSUB_H
+#define MPLAYER_DVBSUB_H
+
+#include <stdint.h>
+#include "libass/ass.h"
+
+typedef struct dvbsus_frame dvbsub_frame_t;
+
+extern dvbsub_frame_t *dvbsub_frames;
+
+void dvbsub_configure(int w, int h);
+void dvbsub_init(void *extradata, int extradata_size);
+void dvbsub_reset(void);
+void dvbsub_process_packet(uint8_t *packet, int size, double pts);
+ass_image_t *dvbsub_render_frame(double pts);
+
+#endif /* MPLAYER_DVBSUB_H */
diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c
index f33aba4..6640aef 100644
--- a/libmpcodecs/vf_ass.c
+++ b/libmpcodecs/vf_ass.c
@@ -41,6 +41,8 @@
#include "m_option.h"
#include "m_struct.h"
+#include "dvbsub.h"
+
#include "libass/ass.h"
#include "libass/ass_mp.h"
@@ -97,6 +99,7 @@ static int config(struct vf_instance_s* vf,
ass_configure(vf->priv->ass_priv, vf->priv->outw, vf->priv->outh, 0);
ass_set_aspect_ratio(vf->priv->ass_priv, ((double)d_width) / d_height);
}
+ dvbsub_configure(vf->priv->outw, vf->priv->outh);
return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, d_height, flags, outfmt);
}
@@ -327,9 +330,12 @@ static int render_frame(struct vf_instance_s* vf, mp_image_t *mpi, const ass_ima
static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts)
{
ass_image_t* images = 0;
- if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE))
- images = ass_mp_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, NULL);
-
+ if (sub_visibility && (pts != MP_NOPTS_VALUE)) {
+ if (dvbsub_frames)
+ images = dvbsub_render_frame(pts);
+ else if (vf->priv->ass_priv && ass_track)
+ images = ass_mp_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, NULL);
+ }
prepare_image(vf, mpi);
if (images) render_frame(vf, mpi, images);
diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c
index 9749054..1169636 100644
--- a/libmpdemux/demux_lavf.c
+++ b/libmpdemux/demux_lavf.c
@@ -386,6 +386,8 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) {
type = 'a';
else if(codec->codec_id == CODEC_ID_DVD_SUBTITLE)
type = 'v';
+ else if(codec->codec_id == CODEC_ID_DVB_SUBTITLE)
+ type = 'b';
else
break;
sh_sub = new_sh_sub_sid(demuxer, i, priv->sub_streams);
@@ -397,6 +399,10 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) {
sh_sub->extradata = malloc(codec->extradata_size);
memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size);
sh_sub->extradata_len = codec->extradata_size;
+ } else if(codec->codec_id == CODEC_ID_DVB_SUBTITLE) {
+ sh_sub->extradata_len = sizeof(int);
+ sh_sub->extradata = malloc(sh_sub->extradata_len);
+ *(int *)sh_sub->extradata = codec->sub_id;
}
if (st->language)
sh_sub->lang = strdup(st->language);
diff --git a/mp_msg.h b/mp_msg.h
index 0f2776f..2ba6d7c 100644
--- a/mp_msg.h
+++ b/mp_msg.h
@@ -104,6 +104,8 @@ extern int verbose;
#define MSGT_STATUSLINE 45 // playback/encoding status line
+# define MSGT_DVBSUB 46 // DVB subtitles
+
#define MSGT_MAX 64
void mp_msg_init(void);
diff --git a/mpcommon.c b/mpcommon.c
index 1165fc4..673d3f1 100644
--- a/mpcommon.c
+++ b/mpcommon.c
@@ -11,6 +11,7 @@
#include "spudec.h"
#include "version.h"
#include "vobsub.h"
+#include "dvbsub.h"
#ifdef CONFIG_TV_TELETEXT
#include "stream/tv.h"
#endif
@@ -66,7 +67,6 @@ if (HAVE_CMOV)
#endif /* ARCH_X86 */
}
-
void update_subtitles(sh_video_t *sh_video, demux_stream_t *d_dvdsub, int reset)
{
unsigned char *packet=NULL;
@@ -144,7 +144,7 @@ void update_subtitles(sh_video_t *sh_video, demux_stream_t *d_dvdsub, int reset)
if (spudec_changed(vo_spudec))
vo_osd_changed(OSDTYPE_SPU);
- } else if (dvdsub_id >= 0 && (type == 't' || type == 'm' || type == 'a')) {
+ } else if (dvdsub_id >= 0 && (type == 't' || type == 'm' || type == 'a' || type == 'b')) {
double curpts = sh_video->pts + sub_delay;
double endpts;
vo_sub = &subs;
@@ -168,6 +168,8 @@ void update_subtitles(sh_video_t *sh_video, demux_stream_t *d_dvdsub, int reset)
ass_process_chunk(ass_track, packet, len,
(long long)(pts*1000 + 0.5),
(long long)((endpts-pts)*1000 + 0.5));
+ } else if (type == 'b') { // DVB subs
+ dvbsub_process_packet(packet, len, pts);
} else { // plaintext subs with libass
vo_sub = NULL;
if (pts != MP_NOPTS_VALUE) {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20090228/eaf2e63c/attachment.pgp>
More information about the MPlayer-dev-eng
mailing list