[MPlayer-dev-eng] [RFC] subtitle code in mencoder

Reimar D?ffinger Reimar.Doeffinger at stud.uni-karlsruhe.de
Thu Feb 8 15:16:45 CET 2007


Hello,
attached patch is supposed to make embedded subs work again with
mencoder while sharing code with mplayer.
The changes from the previous patch are also in this one (sorry, too
lazy to clean it up properly).
There is some weird bug though: the first time a subtitle appears almost
the whole picture is overwritten with black...
Ideas, suggestions, comments?

Greetings,
Reimar Döffinger
-------------- next part --------------
Index: mplayer.c
===================================================================
--- mplayer.c	(revision 22173)
+++ mplayer.c	(working copy)
@@ -418,6 +419,10 @@
 int use_filedir_conf;
 
 static unsigned int inited_flags=0;
+sub_data* subdata = NULL;
+static subtitle* vo_sub_last = NULL;
+
+#include "mp_common.c"
 #define INITED_VO 1
 #define INITED_AO 2
 #define INITED_GUI 4
@@ -966,9 +971,6 @@
     return source;
 }
 
-sub_data* subdata = NULL;
-static subtitle* vo_sub_last = NULL;
-
 void add_subtitles(char *filename, float fps, int silent)
 {
     sub_data *subd;
@@ -2364,14 +2366,12 @@
 #ifdef USE_DVDREAD
             if (vo_spudec && stream->type == STREAMTYPE_DVD) {
                 d_dvdsub->id = dvdsub_id;
-                spudec_reset(vo_spudec);
             }
 #endif
 
 #ifdef USE_DVDNAV
             if (vo_spudec && stream->type == STREAMTYPE_DVDNAV) {
                 d_dvdsub->id = dvdsub_id;
-                spudec_reset(vo_spudec);
             }
 #endif
             if (stream->type != STREAMTYPE_DVD && stream->type != STREAMTYPE_DVDNAV) {
@@ -2397,17 +2397,14 @@
 #endif
             }
         }
-    } else { // off
-        vo_osd_changed(OSDTYPE_SUBTITLE);
-        if(vo_spudec) vo_osd_changed(OSDTYPE_SPU);
     }
 #ifdef USE_DVDREAD
     if (vo_spudec && (stream->type == STREAMTYPE_DVD || stream->type == STREAMTYPE_DVDNAV) && dvdsub_id < 0 && reset_spu) {
         dvdsub_id = -2;
         d_dvdsub->id = dvdsub_id;
-        spudec_reset(vo_spudec);
     }
 #endif
+    update_subtitles(1);
 
     return M_PROPERTY_OK;
 }
@@ -2894,115 +2891,6 @@
 	audio_out->get_delay();
 }
 
-static void update_subtitles(void)
-{
-    unsigned char *packet=NULL;
-    int len;
-    char type = d_dvdsub->sh ? ((sh_sub_t *)d_dvdsub->sh)->type : 'v';
-    if (type == 'a')
-#ifdef USE_ASS
-      if (!ass_enabled)
-#endif
-      type = 't';
-    // find sub
-    if (subdata) {
-	double pts = sh_video->pts;
-	if (sub_fps==0) sub_fps = sh_video->fps;
-	current_module = "find_sub";
-	if (pts > sub_last_pts || pts < sub_last_pts-1.0) {
-	    find_sub(subdata, (pts+sub_delay) *
-		     (subdata->sub_uses_time ? 100. : sub_fps)); 
-	    if (vo_sub) vo_sub_last = vo_sub;
-	    // FIXME! frame counter...
-	    sub_last_pts = pts;
-	}
-    }
-
-    // DVD sub:
-    if (vo_config_count && vo_spudec && type == 'v') {
-	int timestamp;
-	current_module = "spudec";
-	spudec_heartbeat(vo_spudec, 90000*sh_video->timer);
-	/* Get a sub packet from the DVD or a vobsub and make a timestamp
-	 * relative to sh_video->timer */
-	while(1) {
-	    // Vobsub
-	    len = 0;
-	    if (vo_vobsub) {
-		if (sh_video->pts+sub_delay >= 0) {
-		    len = vobsub_get_packet(vo_vobsub, sh_video->pts+sub_delay,
-					    (void**)&packet, &timestamp);
-		    if (len > 0) {
-			timestamp -= (sh_video->pts + sub_delay - sh_video->timer)*90000;
-			mp_dbg(MSGT_CPLAYER,MSGL_V,"\rVOB sub: len=%d v_pts=%5.3f v_timer=%5.3f sub=%5.3f ts=%d \n",len,sh_video->pts,sh_video->timer,timestamp / 90000.0,timestamp);
-		    }
-		}
-	    } else {
-		// DVD sub
-		len = ds_get_packet_sub(d_dvdsub, (unsigned char**)&packet);
-		if (len > 0) {
-		    // XXX This is wrong, sh_video->pts can be arbitrarily
-		    // much behind demuxing position. Unfortunately using
-		    // d_video->pts which would have been the simplest
-		    // improvement doesn't work because mpeg specific hacks
-		    // in video.c set d_video->pts to 0.
-		    float x = d_dvdsub->pts - sh_video->pts;
-		    if (x > -20 && x < 20) // prevent missing subs on pts reset
-			timestamp = 90000*(sh_video->timer + d_dvdsub->pts
-					   + sub_delay - sh_video->pts);
-		    else timestamp = 90000*(sh_video->timer + sub_delay);
-		    mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d  "
-			   "v_pts=%5.3f  s_pts=%5.3f  ts=%d \n", len,
-			   sh_video->pts, d_dvdsub->pts, timestamp);
-		}
-	    }
-	    if (len<=0 || !packet) break;
-	    if (timestamp >= 0)
-		spudec_assemble(vo_spudec, packet, len, timestamp);
-	}
-
-	if (spudec_changed(vo_spudec))
-	    vo_osd_changed(OSDTYPE_SPU);
-    } else if (dvdsub_id >= 0 && type == 't') {
-	static subtitle subs;
-	double curpts = sh_video->pts + sub_delay;
-	double endpts;
-	vo_sub = &subs;
-	while (d_dvdsub->first) {
-	    double pts = ds_get_next_pts(d_dvdsub);
-	    if (pts > curpts)
-		break;
-	    endpts = d_dvdsub->first->endpts;
-	    len = ds_get_packet_sub(d_dvdsub, &packet);
-#ifdef USE_ASS
-	    if (ass_enabled) {
-		static ass_track_t *global_ass_track = NULL;
-		if (!global_ass_track) global_ass_track = ass_default_track(ass_library);
-		ass_track = global_ass_track;
-		vo_sub = NULL;
-		if (pts != MP_NOPTS_VALUE) {
-		    if (endpts == MP_NOPTS_VALUE) endpts = pts + 3;
-		    sub_clear_text(&subs, MP_NOPTS_VALUE);
-		    sub_add_text(&subs, packet, len, endpts);
-		    subs.start = pts * 100;
-		    subs.end = endpts * 100;
-		    ass_process_subtitle(ass_track, &subs);
-		}
-	    } else
-#endif
-		if (pts != MP_NOPTS_VALUE) {
-		    if (endpts == MP_NOPTS_VALUE)
-			sub_clear_text(&subs, MP_NOPTS_VALUE);
-		    sub_add_text(&subs, packet, len, endpts);
-		    vo_osd_changed(OSDTYPE_SUBTITLE);
-		}
-	}
-	if (sub_clear_text(&subs, curpts))
-	    vo_osd_changed(OSDTYPE_SUBTITLE);
-    }
-    current_module=NULL;
-}
-
 static int generate_video_frame(sh_video_t *sh_video, demux_stream_t *d_video)
 {
     unsigned char *start;
@@ -3032,7 +2920,7 @@
 	current_module = "decode video";
 	decoded_frame = decode_video(sh_video, start, in_size, 0, pts);
 	if (decoded_frame) {
-	    update_subtitles();
+	    update_subtitles(0);
 	    update_osd_msg();
 	    current_module = "filter video";
 	    if (filter_video(sh_video, decoded_frame, sh_video->pts))
@@ -3462,7 +3372,7 @@
 		drop_frame = dropped_frames = 0;
 	    ++total_frame_cnt;
 	}
-	update_subtitles();
+	update_subtitles(0);
 	update_osd_msg();
 	current_module = "decode_video";
 	decoded_frame = decode_video(sh_video, start, in_size, drop_frame,
@@ -5629,7 +5539,7 @@
 	audio_time_usage=0; video_time_usage=0; vout_time_usage=0;
 	drop_frame_cnt=0;
 
-        if(vo_spudec) spudec_reset(vo_spudec);
+        update_subtitles(1);
       }
   }
 /*
Index: mencoder.c
===================================================================
--- mencoder.c	(revision 22173)
+++ mencoder.c	(working copy)
@@ -295,6 +295,16 @@
 #include "vobsub.h"
 
 #include "libao2/audio_out.h"
+
+static demux_stream_t *d_audio;
+static demux_stream_t *d_video;
+static demux_stream_t *d_dvdsub;
+static sh_audio_t *sh_audio;
+static sh_video_t *sh_video;
+static subtitle *vo_sub_last;
+static char *current_module;
+#include "mp_common.c"
+
 /* FIXME */
 static void mencoder_exit(int level, const char *how)
 {
@@ -369,11 +379,6 @@
 demuxer_t* demuxer=NULL;
 stream_t* stream2=NULL;
 demuxer_t* demuxer2=NULL;
-demux_stream_t *d_audio=NULL;
-demux_stream_t *d_video=NULL;
-demux_stream_t *d_dvdsub=NULL;
-sh_audio_t *sh_audio=NULL;
-sh_video_t *sh_video=NULL;
 int file_format=DEMUXER_TYPE_UNKNOWN;
 int i=DEMUXER_TYPE_UNKNOWN;
 void *vobsub_writer=NULL;
@@ -1483,22 +1488,17 @@
 
 #ifdef USE_DVDREAD
 // DVD sub:
- if(vo_spudec||vobsub_writer){
+ if(vobsub_writer){
      unsigned char* packet=NULL;
      int len;
      while((len=ds_get_packet_sub(d_dvdsub,&packet))>0){
 	 mp_msg(MSGT_MENCODER,MSGL_V,"\rDVD sub: len=%d  v_pts=%5.3f  s_pts=%5.3f  \n",len,sh_video->pts,d_dvdsub->pts);
-	 if (vo_spudec)
-	 spudec_assemble(vo_spudec,packet,len,90000*d_dvdsub->pts);
-	 if (vobsub_writer)
 	     vobsub_out_output(vobsub_writer,packet,len,mux_v->timer + d_dvdsub->pts - sh_video->pts);
      }
-     if (vo_spudec) {
-     spudec_heartbeat(vo_spudec,90000*sh_video->pts);
-     vo_osd_changed(OSDTYPE_SPU);
-     }
  }
+ else
 #endif
+    update_subtitles(0);
 
  frame_data = (s_frame_data){ .start = NULL, .in_size = 0, .frame_time = 0., .already_read = 0 };
 
Index: mp_common.c
===================================================================
--- mp_common.c	(revision 0)
+++ mp_common.c	(revision 0)
@@ -0,0 +1,119 @@
+static void update_subtitles(int reset)
+{
+    unsigned char *packet=NULL;
+    int len;
+    char type = d_dvdsub->sh ? ((sh_sub_t *)d_dvdsub->sh)->type : 'v';
+    static subtitle subs;
+    if (type == 'a')
+#ifdef USE_ASS
+      if (!ass_enabled)
+#endif
+      type = 't';
+    if (reset) {
+	sub_clear_text(&subs, MP_NOPTS_VALUE);
+	if (vo_sub) {
+	    vo_sub = NULL;
+	    vo_osd_changed(OSDTYPE_SUBTITLE);
+	}
+	if (vo_spudec) {
+	    spudec_reset(vo_spudec);
+	    vo_osd_changed(OSDTYPE_SPU);
+	}
+    }
+    // find sub
+    if (subdata) {
+	double pts = sh_video->pts;
+	if (sub_fps==0) sub_fps = sh_video->fps;
+	current_module = "find_sub";
+	if (pts > sub_last_pts || pts < sub_last_pts-1.0) {
+	    find_sub(subdata, (pts+sub_delay) *
+		     (subdata->sub_uses_time ? 100. : sub_fps)); 
+	    if (vo_sub) vo_sub_last = vo_sub;
+	    // FIXME! frame counter...
+	    sub_last_pts = pts;
+	}
+    }
+
+    // DVD sub:
+    if (vo_config_count && vo_spudec && type == 'v') {
+	int timestamp;
+	current_module = "spudec";
+	spudec_heartbeat(vo_spudec, 90000*sh_video->timer);
+	/* Get a sub packet from the DVD or a vobsub and make a timestamp
+	 * relative to sh_video->timer */
+	while(1) {
+	    // Vobsub
+	    len = 0;
+	    if (vo_vobsub) {
+		if (sh_video->pts+sub_delay >= 0) {
+		    len = vobsub_get_packet(vo_vobsub, sh_video->pts+sub_delay,
+					    (void**)&packet, &timestamp);
+		    if (len > 0) {
+			timestamp -= (sh_video->pts + sub_delay - sh_video->timer)*90000;
+			mp_dbg(MSGT_CPLAYER,MSGL_V,"\rVOB sub: len=%d v_pts=%5.3f v_timer=%5.3f sub=%5.3f ts=%d \n",len,sh_video->pts,sh_video->timer,timestamp / 90000.0,timestamp);
+		    }
+		}
+	    } else {
+		// DVD sub
+		len = ds_get_packet_sub(d_dvdsub, (unsigned char**)&packet);
+		if (len > 0) {
+		    // XXX This is wrong, sh_video->pts can be arbitrarily
+		    // much behind demuxing position. Unfortunately using
+		    // d_video->pts which would have been the simplest
+		    // improvement doesn't work because mpeg specific hacks
+		    // in video.c set d_video->pts to 0.
+		    float x = d_dvdsub->pts - sh_video->pts;
+		    if (x > -20 && x < 20) // prevent missing subs on pts reset
+			timestamp = 90000*(sh_video->timer + d_dvdsub->pts
+					   + sub_delay - sh_video->pts);
+		    else timestamp = 90000*(sh_video->timer + sub_delay);
+		    mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d  "
+			   "v_pts=%5.3f  s_pts=%5.3f  ts=%d \n", len,
+			   sh_video->pts, d_dvdsub->pts, timestamp);
+		}
+	    }
+	    if (len<=0 || !packet) break;
+	    if (timestamp >= 0)
+		spudec_assemble(vo_spudec, packet, len, timestamp);
+	}
+
+	if (spudec_changed(vo_spudec))
+	    vo_osd_changed(OSDTYPE_SPU);
+    } else if (dvdsub_id >= 0 && type == 't') {
+	double curpts = sh_video->pts + sub_delay;
+	double endpts;
+	vo_sub = &subs;
+	while (d_dvdsub->first) {
+	    double pts = ds_get_next_pts(d_dvdsub);
+	    if (pts > curpts)
+		break;
+	    endpts = d_dvdsub->first->endpts;
+	    len = ds_get_packet_sub(d_dvdsub, &packet);
+#ifdef USE_ASS
+	    if (ass_enabled) {
+		static ass_track_t *global_ass_track = NULL;
+		if (!global_ass_track) global_ass_track = ass_default_track(ass_library);
+		ass_track = global_ass_track;
+		vo_sub = NULL;
+		if (pts != MP_NOPTS_VALUE) {
+		    if (endpts == MP_NOPTS_VALUE) endpts = pts + 3;
+		    sub_clear_text(&subs, MP_NOPTS_VALUE);
+		    sub_add_text(&subs, packet, len, endpts);
+		    subs.start = pts * 100;
+		    subs.end = endpts * 100;
+		    ass_process_subtitle(ass_track, &subs);
+		}
+	    } else
+#endif
+		if (pts != MP_NOPTS_VALUE) {
+		    if (endpts == MP_NOPTS_VALUE)
+			sub_clear_text(&subs, MP_NOPTS_VALUE);
+		    sub_add_text(&subs, packet, len, endpts);
+		    vo_osd_changed(OSDTYPE_SUBTITLE);
+		}
+	}
+	if (sub_clear_text(&subs, curpts))
+	    vo_osd_changed(OSDTYPE_SUBTITLE);
+    }
+    current_module=NULL;
+}


More information about the MPlayer-dev-eng mailing list