[MPlayer-dev-eng] [PATCH] Support for DVB subtitles
Nicolas George
nicolas.george at normalesup.org
Sat Feb 28 16:11:20 CET 2009
Le decadi 10 ventôse, an CCXVII, Diego Biurrun a écrit :
> nit: one more occasion:
Done.
> But don't bother sending an update just for this, I bet there will be
> more comments.
There was a small endianness mistake in the palette handling anyway.
Corrected version attached.
Regards,
--
Nicolas George
-------------- next part --------------
Makefile | 1 +
command.c | 4 +
dvbsub.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++
dvbsub.h | 40 ++++++++
libmpcodecs/vf_ass.c | 12 ++-
libmpdemux/demux_lavf.c | 3 +
libmpdemux/demuxer.c | 14 +++-
libmpdemux/stheader.h | 3 +
mp_msg.h | 2 +
mpcommon.c | 12 ++-
10 files changed, 320 insertions(+), 9 deletions(-)
diff --git a/Makefile b/Makefile
index 449b058..145a31c 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..7d571d9 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_current = NULL;
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_current = sh->dvbsub_track;
#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..5ea5f36
--- /dev/null
+++ b/dvbsub.c
@@ -0,0 +1,238 @@
+/*
+ * DVB subtitles
+ *
+ * Copyright (C) 2009 Nicolas George
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "mplayer.h"
+#include "mp_msg.h"
+#include "libavcodec/avcodec.h"
+#include "dvbsub.h"
+
+struct dvbsub_track {
+ struct dvbsub_frame *frames;
+ AVCodecContext *decoder;
+ ass_image_t *images;
+ int frame_w;
+ int frame_h;
+ int rendered;
+};
+
+struct dvbsub_frame {
+ struct dvbsub_frame *next;
+ AVSubtitleRect **rect;
+ float start, end;
+ int n_rect;
+};
+
+struct dvbsub_track *dvbsub_current = NULL;
+
+static void dvbsub_invalidate_images(struct dvbsub_track *track)
+{
+ ass_image_t *ni;
+
+ track->rendered = 0;
+ while (track->images) {
+ ni = track->images->next;
+ free(track->images->bitmap);
+ free(track->images);
+ track->images = ni;
+ }
+}
+
+static void dvbsub_free_frame(struct dvbsub_frame *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);
+}
+
+struct dvbsub_track *dvbsub_create(int sub_id)
+{
+ struct dvbsub_track *track;
+ int r;
+ AVCodec *codec;
+
+ track = malloc(sizeof(struct dvbsub_track));
+ if (track == NULL)
+ return NULL;
+ track->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");
+ free(track);
+ return NULL;
+ }
+ track->decoder->sub_id = sub_id;
+ r = avcodec_open(track->decoder, codec);
+ if (r < 0) {
+ mp_msg(MSGT_DVBSUB, MSGL_ERR, "dvbsub decoder not opened\n");
+ av_free(track->decoder);
+ free(track);
+ return NULL;
+ }
+ track->frames = NULL;
+ track->images = NULL;
+ track->rendered = 0;
+ track->frame_w = 720;
+ track->frame_h = 576;
+ return track;
+}
+
+void dvbsub_destroy(struct dvbsub_track *track)
+{
+ struct dvbsub_frame *nf;
+
+ dvbsub_invalidate_images(track);
+ while (track->frames) {
+ nf = track->frames->next;
+ dvbsub_free_frame(track->frames);
+ track->frames = nf;
+ }
+}
+
+static void dvbsub_add_frame(struct dvbsub_track *track,
+ double start, double end,
+ AVSubtitleRect **rect, int n_rect)
+{
+ struct dvbsub_frame *frame, *f, **prev, *nf;
+
+ frame = malloc(sizeof(struct dvbsub_frame));
+ if (frame == NULL)
+ return;
+ frame->start = start;
+ frame->end = end;
+ frame->rect = rect;
+ frame->n_rect = n_rect;
+
+ f = track->frames;
+ prev = &track->frames;
+ for (f = track->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(track);
+}
+
+void dvbsub_process_packet(struct dvbsub_track *track,
+ uint8_t *packet, int size, double pts)
+{
+ int r, got_sub = 0;
+ AVSubtitle sub;
+
+ r = avcodec_decode_subtitle(track->decoder, &sub, &got_sub, packet, size);
+ if (!got_sub)
+ return;
+ if (sub.format != 0)
+ return;
+ dvbsub_add_frame(track, 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(struct dvbsub_track *track, double pts,
+ int frame_w, int frame_h)
+{
+ struct dvbsub_frame *frame, *nf;
+ ass_image_t *ni, **tail;
+ int i, psize, x, y, w, h, dx, dy, stride;
+ uint32_t *palette;
+ uint8_t *src, *dst;
+
+ if (track->frame_w != frame_w || track->frame_h != frame_h) {
+ dvbsub_invalidate_images(track);
+ track->frame_w = frame_w;
+ track->frame_h = frame_h;
+ }
+ pts += sub_delay;
+ while (track->frames && track->frames->end < pts) {
+ nf = track->frames->next;
+ dvbsub_free_frame(track->frames);
+ dvbsub_invalidate_images(track);
+ track->frames = nf;
+ }
+ if (track->rendered)
+ return track->images;
+ frame = track->frames;
+ tail = &track->images;
+ if (frame) {
+ for (i = 0; i < frame->n_rect; i++) {
+ palette = (uint32_t *)frame->rect[i]->pict.data[1];
+ psize = frame->rect[i]->nb_colors;
+ x = frame->rect[i]->x;
+ y = frame->rect[i]->y;
+ w = frame->rect[i]->w;
+ h = frame->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 > track->frame_h)
+ h = track->frame_h - y;
+ if (w < 0 || h < 0)
+ continue;
+ stride = frame->rect[i]->pict.linesize[0];
+ src = frame->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++)] >> 24;
+ src += stride - w;
+ }
+ ni->color = (palette[psize - 1] & 0xFFFFFF) << 8;
+ *tail = ni;
+ tail = &ni->next;
+ }
+ }
+ *tail = NULL;
+ track->rendered = 1;
+ return track->images;
+}
diff --git a/dvbsub.h b/dvbsub.h
new file mode 100644
index 0000000..f2e0c5c
--- /dev/null
+++ b/dvbsub.h
@@ -0,0 +1,40 @@
+/*
+ * DVB subtitles
+ *
+ * Copyright (C) 2009 Nicolas George
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_DVBSUB_H
+#define MPLAYER_DVBSUB_H
+
+#include <stdint.h>
+#include "libass/ass.h"
+
+struct dvbsub_track;
+
+extern struct dvbsub_track *dvbsub_current;
+
+struct dvbsub_track *dvbsub_create(int sub_id);
+void dvbsub_destroy(struct dvbsub_track *track);
+void dvbsub_process_packet(struct dvbsub_track *track,
+ uint8_t *packet, int size, double pts);
+ass_image_t *dvbsub_render_frame(struct dvbsub_track *track, double pts,
+ int frame_w, int frame_h);
+
+#endif /* MPLAYER_DVBSUB_H */
diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c
index f33aba4..2513481 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"
@@ -327,9 +329,13 @@ 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_current)
+ images = dvbsub_render_frame(dvbsub_current, pts,
+ vf->priv->outw, vf->priv->outh);
+ 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..ffe04d1 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);
@@ -398,6 +400,7 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) {
memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size);
sh_sub->extradata_len = codec->extradata_size;
}
+ sh_sub->sub_id = codec->sub_id;
if (st->language)
sh_sub->lang = strdup(st->language);
if (st->disposition & AV_DISPOSITION_DEFAULT)
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index 74bbd8e..206a93c 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -22,6 +22,7 @@
#include "libaf/af_format.h"
+#include "dvbsub.h"
#ifdef CONFIG_ASS
#include "libass/ass.h"
#include "libass/ass_mp.h"
@@ -272,6 +273,8 @@ void free_sh_sub(sh_sub_t *sh)
if (sh->ass_track)
ass_free_track(sh->ass_track);
#endif
+ if (sh->dvbsub_track)
+ dvbsub_destroy(sh->dvbsub_track);
free(sh->lang);
free(sh);
}
@@ -914,13 +917,20 @@ static demuxer_t *demux_open_stream(stream_t *stream, int file_format,
if (ass_enabled && ass_library) {
for (i = 0; i < MAX_S_STREAMS; ++i) {
sh_sub_t *sh = demuxer->s_streams[i];
- if (sh && sh->type == 'a') {
+ if (!sh)
+ continue;
+ if (sh->type == 'a') {
sh->ass_track = ass_new_track(ass_library);
if (sh->ass_track && sh->extradata)
ass_process_codec_private(sh->ass_track, sh->extradata,
sh->extradata_len);
- } else if (sh && sh->type != 'v')
+ } else if (sh->type == 'v') {
+ /* nothing */
+ } else if (sh->type == 'b') {
+ sh->dvbsub_track = dvbsub_create(sh->sub_id);
+ } else {
sh->ass_track = ass_default_track(ass_library);
+ }
}
}
#endif
diff --git a/libmpdemux/stheader.h b/libmpdemux/stheader.h
index 07ecfae..178aeef 100644
--- a/libmpdemux/stheader.h
+++ b/libmpdemux/stheader.h
@@ -4,6 +4,7 @@
#include "demuxer.h"
#include "aviheader.h"
#include "ms_hdr.h"
+#include "dvbsub.h"
// Stream headers:
@@ -99,9 +100,11 @@ typedef struct {
char type; // t = text, v = VobSub, a = SSA/ASS
unsigned char* extradata; // extra header data passed from demuxer
int extradata_len;
+ int sub_id; // sub_id passed from demuxer
#ifdef CONFIG_ASS
ass_track_t* ass_track; // for SSA/ASS streams (type == 'a')
#endif
+ struct dvbsub_track *dvbsub_track;
char* lang; // track language
int default_track;
} sh_sub_t;
diff --git a/mp_msg.h b/mp_msg.h
index 0f2776f..ee6919d 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..0c8646c 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
@@ -144,7 +145,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;
@@ -163,12 +164,15 @@ void update_subtitles(sh_video_t *sh_video, demux_stream_t *d_dvdsub, int reset)
if (ass_enabled) {
sh_sub_t* sh = d_dvdsub->sh;
ass_track = sh ? sh->ass_track : NULL;
- if (!ass_track) continue;
- if (type == 'a') { // ssa/ass subs with libass
+ if (ass_track && type == 'a') { // ssa/ass subs with libass
ass_process_chunk(ass_track, packet, len,
(long long)(pts*1000 + 0.5),
(long long)((endpts-pts)*1000 + 0.5));
- } else { // plaintext subs with libass
+ } else if (type == 'b') { // DVB subs
+ if (sh && sh->dvbsub_track)
+ dvbsub_process_packet(sh->dvbsub_track,
+ packet, len, pts);
+ } else if (ass_track) { // plaintext subs with libass
vo_sub = NULL;
if (pts != MP_NOPTS_VALUE) {
if (endpts == MP_NOPTS_VALUE) endpts = pts + 3;
-------------- 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/ddb132f9/attachment.pgp>
More information about the MPlayer-dev-eng
mailing list