[MPlayer-dev-eng] [PATCH] mencoder output only forced subtitles using -forcedsubsonly

Rob McMullen robm at users.sourceforge.net
Mon Apr 12 20:44:40 CEST 2010


Here's a patch to get mencoder to honor the -forcedsubsonly command
line option and will output only the forced subtitles to the .idx/.sub
file.  Without the -forcedsubsonly argument, the full .idx/.sub are
output as usual.

In order to implement this, I had to modify vobsub_out_output to use
the spudec routines to decode the subtitle stream so that the writer
can determine if the subtitle is forced or not.  Because all the info
in spudec_handle_t is private, I added two new functions in spudec.c:
spudec_is_valid and spudec_is_forced_sub.  Those simply access the
private vars and return true/false.

When -forcedsubsonly is enabled, the vobsub_out_output modifications
were designed to minimize the changes needed in the writing logic.
Because you can't tell if a subtitle is forced or not until the packet
is complete and decoded, a subtitle might be spread across multiple
calls to vobsub_out_output.

Therefore, all packets are written out to the .sub file until the
spudec_assemble process determines that the packet is complete.  Once
it is complete, the new spudec_is_forced_sub function is called.  If
it is NOT a forced subtitle, the .sub files is rewound so that those
packets will be overwritten and the .idx file is rewound to remove
that timestamp/filepos entry.

I also had to modify vobsub_out_open to use "r+b" or "wb" (depending
on if the file exists or not) in the fopen call instead of "ab",
because "ab" causes every write to occur at the end of the file
regardless of any calls to fseek.

Can test with a command line like:

mencoder d9.vob -vobsubout d9.forcedsubsonly -vobsuboutindex 0
-vobsuboutid en -sid 0 -nosound -ovc frameno -o /dev/null -msglevel
vobsub=9 -forcedsubsonly

Rob
-------------- next part --------------
Index: vobsub.c
===================================================================
--- vobsub.c	(revision 31032)
+++ vobsub.c	(working copy)
@@ -1232,6 +1232,9 @@
     FILE *fsub;
     FILE *fidx;
     unsigned int aid;
+    void *vo_spudec;
+    long last_good_sub_loc;
+    long last_good_idx_loc;
 } vobsub_out_t;
 
 static void create_idx(vobsub_out_t *me, const unsigned int *palette,
@@ -1269,7 +1272,8 @@
 
 void *vobsub_out_open(const char *basename, const unsigned int *palette,
                       unsigned int orig_width, unsigned int orig_height,
-                      const char *id, unsigned int index)
+                      const char *id, unsigned int index,
+                      unsigned int forced_subs_only)
 {
     vobsub_out_t *result = NULL;
     char *filename;
@@ -1280,13 +1284,28 @@
             result->aid = index;
             strcpy(filename, basename);
             strcat(filename, ".sub");
-            result->fsub = fopen(filename, "ab");
+            /* writing only forced subs requires seeking in the open stream.
+               If "ab" is used in fopen, all writes are performed at the
+               end of the stream regardless of calls to fseek, so the files
+               must be opened in "r+b" mode (or "wb" mode if the file is new)
+               and positioned at the end of file.
+            */
+            result->fsub = fopen(filename, "r+b");
             if (result->fsub == NULL)
+                result->fsub = fopen(filename, "wb");
+            if (result->fsub == NULL)
                 perror("Error: vobsub_out_open subtitle file open failed");
+            else {
+                fseek(result->fsub, 0, SEEK_END);
+                result->last_good_sub_loc = ftell(result->fsub);
+            }
             strcpy(filename, basename);
             strcat(filename, ".idx");
-            result->fidx = fopen(filename, "ab");
+            result->fidx = fopen(filename, "r+b");
+            if (result->fidx == NULL)
+                result->fidx = fopen(filename, "wb");
             if (result->fidx) {
+                fseek(result->fidx, 0, SEEK_END);
                 if (ftell(result->fidx) == 0) {
                     create_idx(result, palette, orig_width, orig_height);
                     /* Make the selected language the default language */
@@ -1295,11 +1314,15 @@
                 fprintf(result->fidx, "\nid: %s, index: %u\n", id ? id : "xx", index);
                 /* So that we can check the file now */
                 fflush(result->fidx);
+                result->last_good_idx_loc = ftell(result->fidx);
             } else
                 perror("Error: vobsub_out_open index file open failed");
             free(filename);
         }
     }
+    /* writing only forced_subs requires spudec decoding of subtitle packets */
+    if (forced_subs_only)
+        result->vo_spudec = spudec_new(NULL);
     return result;
 }
 
@@ -1310,6 +1333,8 @@
         fclose(vob->fidx);
     if (vob->fsub)
         fclose(vob->fsub);
+    if (vob->vo_spudec)
+        spudec_free(vob->vo_spudec);
     free(vob);
 }
 
@@ -1436,5 +1461,24 @@
             fprintf(stderr,
                     "\nERROR: wrong thing happenned...\n"
                     "  I wrote a %i data bytes spu packet and that's too long\n", len);
+        
+        if (vob->vo_spudec) {
+            spudec_assemble(vob->vo_spudec, packet, len, pts);
+            if (spudec_is_valid(vob->vo_spudec)) {
+                if (spudec_is_forced_sub(vob->vo_spudec)) {
+                    if (vob->fsub)
+                        vob->last_good_sub_loc = ftell(vob->fsub);
+                    if (vob->fidx)
+                        vob->last_good_idx_loc = ftell(vob->fidx);
+                    mp_msg(MSGT_VOBSUB, MSGL_DBG3, "vobsub_out_output: forced sub!  next file position: sub=%ld idx=%ld\n", vob->last_good_sub_loc, vob->last_good_idx_loc);
+                } else {
+                    mp_msg(MSGT_VOBSUB, MSGL_DBG3, "vobsub_out_output: non-forced sub.  Removing from output and rewinding to: sub=%ld idx=%ld.\n", vob->last_good_sub_loc, vob->last_good_idx_loc);
+                    if (vob->fsub)
+                        fseek(vob->fsub, vob->last_good_sub_loc, SEEK_SET);
+                    if (vob->fidx)
+                        fseek(vob->fidx, vob->last_good_idx_loc, SEEK_SET);
+                }
+            }
+        }
     }
 }
Index: vobsub.h
===================================================================
--- vobsub.h	(revision 31032)
+++ vobsub.h	(working copy)
@@ -38,7 +38,7 @@
 /// Convert rgb value to yuv.
 unsigned int vobsub_rgb_to_yuv(unsigned int rgb);
 
-void *vobsub_out_open(const char *basename, const unsigned int *palette, unsigned int orig_width, unsigned int orig_height, const char *id, unsigned int index);
+void *vobsub_out_open(const char *basename, const unsigned int *palette, unsigned int orig_width, unsigned int orig_height, const char *id, unsigned int index, unsigned int forced_subs_only);
 void vobsub_out_output(void *me, const unsigned char *packet, int len, double pts);
 void vobsub_out_close(void *me);
 int vobsub_set_from_lang(void *vobhandle, unsigned char * lang);
Index: spudec.c
===================================================================
--- spudec.c	(revision 31032)
+++ spudec.c	(working copy)
@@ -649,6 +649,23 @@
   }
 }
 
+unsigned int spudec_is_forced_sub(void * const this)
+{
+  if(this){
+    return ((spudec_handle_t *)this)->is_forced_sub;
+  }
+  return 0;
+}
+
+unsigned int spudec_is_valid(void * const this)
+{
+  spudec_handle_t *spu = (spudec_handle_t *)this;
+  if(spu){
+    return (spu->packet_size > 0 && spu->packet_offset == 0);
+  }
+  return 0;
+}
+
 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
 {
     spudec_handle_t *spu = (spudec_handle_t *)this;
Index: spudec.h
===================================================================
--- spudec.h	(revision 31032)
+++ spudec.h	(working copy)
@@ -36,5 +36,7 @@
 int spudec_changed(void *this);
 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox);
 void spudec_set_forced_subs_only(void * const this, const unsigned int flag);
+unsigned int spudec_is_forced_sub(void * const this);
+unsigned int spudec_is_valid(void * const this);
 
 #endif /* MPLAYER_SPUDEC_H */
Index: mencoder.c
===================================================================
--- mencoder.c	(revision 31032)
+++ mencoder.c	(working copy)
@@ -844,7 +844,7 @@
     unsigned char tmp[3] = { 0, 0, 0 };
     if (spudec_ifo && vobsub_parse_ifo(NULL,spudec_ifo, palette, &width, &height, 1, dvdsub_id, tmp) >= 0)
 	vobsub_writer = vobsub_out_open(vobsub_out, palette, sh_video->disp_w, sh_video->disp_h,
-					vobsub_out_id?vobsub_out_id:(char *)tmp, vobsub_out_index);
+					vobsub_out_id?vobsub_out_id:(char *)tmp, vobsub_out_index, forced_subs_only);
 #ifdef CONFIG_DVDREAD
     if (vobsub_writer == NULL) {
 	char tmp[3];
@@ -861,7 +861,7 @@
 		}
 	}
 	vobsub_writer=vobsub_out_open(vobsub_out, stream->type==STREAMTYPE_DVD?((dvd_priv_t *)(stream->priv))->cur_pgc->palette:NULL,
-				      sh_video->disp_w, sh_video->disp_h, vobsub_out_id, vobsub_out_index);
+				      sh_video->disp_w, sh_video->disp_h, vobsub_out_id, vobsub_out_index, forced_subs_only);
     }
 #endif
 }


More information about the MPlayer-dev-eng mailing list