[MPlayer-dev-eng] [PATCH] EDL 0.6 - DVD chapter support (w/ cvs diff -u)

Michael Halcrow mike at halcrow.us
Sat Jul 26 06:23:36 CEST 2003


On Fri, Jul 25, 2003 at 08:39:35PM +0200, Diego Biurrun wrote:
> It's a minor thing, but Gabu has been known to correct two spaces to one and
> I sometimes also do it, so if you could redo the patch that would be very
> nice.
> Thanks

Here it is.  Supporting DVD streams while finding the appropriate
record after a seek was a bit tricky, but it worked with my tests.

Mike

-- 
------------------------------------------- | ---------------------
Michael Halcrow                             | mike at halcrow.us     
Developer, IBM Linux Technology Center      |                      
                                            |
The hokey pokey... What if that's really    |
what it's all about?                        |
------------------------------------------- | ---------------------
GnuPG Keyprint:  05B5 08A8 713A 64C1 D35D  2371 2D3C FDDA 3EB6 601D
-------------- next part --------------
Index: edl.h
===================================================================
RCS file: /cvsroot/mplayer/main/edl.h,v
retrieving revision 1.2
diff -u -r1.2 edl.h
--- edl.h	3 Feb 2003 09:26:40 -0000	1.2
+++ edl.h	26 Jul 2003 02:03:31 -0000
@@ -1,4 +1,4 @@
-// EDL version 0.5
+// EDL version 0.6
 
 #ifndef EDLH
 #define EDLH
@@ -15,6 +15,7 @@
   long stop_frame;
   float length_sec;
   long length_frame;
+  int chapter;
   short action;
   struct edl_record* next;
 };
Index: mplayer.c
===================================================================
RCS file: /cvsroot/mplayer/main/mplayer.c,v
retrieving revision 1.708
diff -u -r1.708 mplayer.c
--- mplayer.c	22 Jul 2003 10:46:22 -0000	1.708
+++ mplayer.c	26 Jul 2003 02:03:37 -0000
@@ -342,6 +342,68 @@
 static char* edl_filename = NULL;
 static char* edl_output_filename = NULL;
 short edl_decision = 0;
+
+enum MuteStates {
+  NOT_MUTED, MUTED_BY_EDL_ONLY, MUTED_BY_USER_ONLY, MUTED_BY_BOTH_EDL_AND_USER
+};
+
+enum MuteRequestors {
+  EDL_MUTE_REQUESTOR, USER_MUTE_REQUESTOR, SKIP_MUTE_REQUESTOR
+};
+
+void toggleMute( enum MuteRequestors muteRequestor ) {
+  static enum MuteStates mute_state = NOT_MUTED;
+  switch( mute_state ) {
+  case NOT_MUTED:
+    if( muteRequestor == EDL_MUTE_REQUESTOR ) {
+      mute_state = MUTED_BY_EDL_ONLY;
+      mixer_mute();
+    } else if( muteRequestor == USER_MUTE_REQUESTOR ) {
+      mute_state = MUTED_BY_USER_ONLY;
+      mixer_mute();
+    } else if( muteRequestor == SKIP_MUTE_REQUESTOR ) {
+      // Do nothing; we're good
+    }
+    break;
+  case MUTED_BY_EDL_ONLY:
+    if( muteRequestor == EDL_MUTE_REQUESTOR ) {
+      mute_state = NOT_MUTED;
+      mixer_mute();
+    } else if( muteRequestor == USER_MUTE_REQUESTOR ) {
+      mute_state = MUTED_BY_BOTH_EDL_AND_USER;
+    } else if( muteRequestor == SKIP_MUTE_REQUESTOR ) {
+      // Clear EDL muted status and unmute
+      mute_state = NOT_MUTED;
+      mixer_mute();      
+    }
+    break;
+  case MUTED_BY_BOTH_EDL_AND_USER:
+    if( muteRequestor == EDL_MUTE_REQUESTOR ) {
+      mute_state = MUTED_BY_USER_ONLY;
+    } else if( muteRequestor == USER_MUTE_REQUESTOR ) {
+      mute_state = MUTED_BY_EDL_ONLY;
+    } else if( muteRequestor == SKIP_MUTE_REQUESTOR ) {
+      // Clear EDL muted status
+      mute_state = MUTED_BY_USER_ONLY;
+    }    
+    break;
+  case MUTED_BY_USER_ONLY:
+    if( muteRequestor == EDL_MUTE_REQUESTOR ) {
+      mute_state = MUTED_BY_BOTH_EDL_AND_USER;      
+    } else if( muteRequestor == USER_MUTE_REQUESTOR ) {
+      mute_state = NOT_MUTED;
+      mixer_mute();
+    } else if( muteRequestor == SKIP_MUTE_REQUESTOR ) {
+      // Do nothing
+    }
+    break;
+  default:
+    printf( "\nUndefined mute state; setting to NOT_MUTED\n" );
+    mute_state = NOT_MUTED;
+    break;
+  }
+}
+
 #endif
 
 static unsigned int inited_flags=0;
@@ -912,11 +974,16 @@
 #endif
 
 #ifdef USE_EDL
+
+#ifndef MAX_EDL_LINE_LENGTH
+#define MAX_EDL_LINE_LENGTH 100
+#endif
+
  {
    FILE* fd;
-   char line[ 100 ];
+   char line[ MAX_EDL_LINE_LENGTH ];
    float start, stop, duration;
-   int action;
+   int chapter, action;
    int next_edl_array_index = 0;
    int lineCount = 0;
    next_edl_record = edl_records;
@@ -925,47 +992,88 @@
        printf( "Error opening EDL file [%s]!\n", edl_filename );
        next_edl_record->next = NULL;
      } else {
-       while( fgets( line, 99, fd ) != NULL ) {
+       while( fgets( line, ( MAX_EDL_LINE_LENGTH - 1 ), fd ) != NULL ) {
+	 int tokenIdx = 0;
+	 char* token;
+	 float vals[ 4 ];
 	 lineCount++;
-	 if( ( sscanf( line, "%f %f %d", &start, &stop, &action ) ) == 0 ) {
-	   printf( "Invalid EDL line: [%s]\n", line );
-	 } else {
-	   if( next_edl_array_index > 0 ) {
-	     edl_records[ next_edl_array_index-1 ].next = &edl_records[ next_edl_array_index ];
-	     if( start <= edl_records[ next_edl_array_index-1 ].stop_sec ) {
-	       printf( "Invalid EDL line [%d]: [%s]\n", lineCount, line );
-	       printf( "Last stop position was [%f]; next start is [%f]. Entries must be in chronological order and cannot overlap. Discarding EDL entry.\n", edl_records[ next_edl_array_index-1 ].stop_sec, start );
-	       continue;
-	     }
+	 chapter = -1;
+
+	 // Read all the tokens
+	 if( ( token = strtok( line, " " ) ) == NULL ) {
+	   printf( "Unable to parse EDL line: [%s]\n", line );
+	   continue;
+	 }
+	 while( token && tokenIdx < 5 ) {
+	   if( strcmp( token, "#" ) == 0 ) {
+	     break;
 	   }
-	   if( stop <= start ) {
-	     printf( "Invalid EDL line [%d]: [%s]\n", lineCount, line );
-	     printf( "Stop time must follow start time. Discarding EDL entry.\n" );
+	   vals[ tokenIdx ] = atof( token );
+	   tokenIdx++;
+	   token = strtok( NULL, " " );
+	 }	 
+	 if( tokenIdx < 3 ) {
+	   printf( "EDL line contains too few tokens: [%s]\n", line );
+	   continue;
+	 }
+	 if( tokenIdx == 3 ) {
+	   // Traditional format
+	   start = vals[ 0 ];
+	   stop = vals[ 1 ];
+	   duration = stop - start;
+	   action = vals[ 2 ];
+	 } else {
+	   // DVD format (with first value being chapter)
+	   chapter = vals[ 0 ];
+	   start = vals[ 1 ];
+	   stop = vals[ 2 ];
+	   duration = stop - start;
+	   action = vals[ 3 ];	   
+	 }
+
+	 if( next_edl_array_index > 0 ) {
+	   edl_records[ next_edl_array_index-1 ].next = &edl_records[ next_edl_array_index ];
+	   if( ( ( chapter != -1 ) &&
+		 chapter < edl_records[ next_edl_array_index-1 ].chapter || 
+		 ( chapter == edl_records[ next_edl_array_index-1 ].chapter && 
+		   start <= edl_records[ next_edl_array_index-1 ].stop_sec ) ) || 
+	       ( ( chapter == -1 ) && 
+		 ( start <= edl_records[ next_edl_array_index-1 ].stop_sec ) ) ) {
+	     printf( "Invalid EDL line [%d]: [%s]; out of chronological order\n", lineCount, line );
+	     printf( "Note that muting across chapter boundaries is currently unsupported for DVD streams\n" );
 	     continue;
 	   }
-	   edl_records[ next_edl_array_index ].action = action;
-	   if( action == EDL_MUTE ) {
-	     edl_records[ next_edl_array_index ].length_sec = 0;
-	     edl_records[ next_edl_array_index ].start_sec = start;
-	     edl_records[ next_edl_array_index ].stop_sec = start;
-	     next_edl_array_index++;
-	     if( next_edl_array_index >= MAX_EDL_ENTRIES-1 ) {
-	       break;
-	     }
-	     edl_records[ next_edl_array_index-1 ].next = &edl_records[ next_edl_array_index ];
-	     edl_records[ next_edl_array_index ].action = EDL_MUTE;
-	     edl_records[ next_edl_array_index ].length_sec = 0;
-	     edl_records[ next_edl_array_index ].start_sec = stop;
-	     edl_records[ next_edl_array_index ].stop_sec = stop;
-	   } else {
-	     edl_records[ next_edl_array_index ].length_sec = stop - start;
-	     edl_records[ next_edl_array_index ].start_sec = start;
-	     edl_records[ next_edl_array_index ].stop_sec = stop;
-	   }
+	 }
+	 if( stop <= start ) {
+	   printf( "Invalid EDL line [%d]: [%s]\n", lineCount, line );
+	   printf( "Stop time must follow start time. Discarding EDL entry.\n" );
+	   printf( "Note that you cannot span across chapter boundaries with EDL entries for DVD streams\n" );
+	   continue;
+	 }
+	 edl_records[ next_edl_array_index ].action = action;
+	 edl_records[ next_edl_array_index ].chapter = chapter;
+	 if( action == EDL_MUTE ) {
+	   edl_records[ next_edl_array_index ].length_sec = 0;
+	   edl_records[ next_edl_array_index ].start_sec = start;
+	   edl_records[ next_edl_array_index ].stop_sec = start;
 	   next_edl_array_index++;
 	   if( next_edl_array_index >= MAX_EDL_ENTRIES-1 ) {
 	     break;
 	   }
+	   edl_records[ next_edl_array_index-1 ].next = &edl_records[ next_edl_array_index ];
+	   edl_records[ next_edl_array_index ].action = EDL_MUTE;
+	   edl_records[ next_edl_array_index ].chapter = edl_records[ next_edl_array_index-1 ].chapter;
+	   edl_records[ next_edl_array_index ].length_sec = 0;
+	   edl_records[ next_edl_array_index ].start_sec = stop;
+	   edl_records[ next_edl_array_index ].stop_sec = stop;
+	 } else {
+	   edl_records[ next_edl_array_index ].length_sec = stop - start;
+	   edl_records[ next_edl_array_index ].start_sec = start;
+	   edl_records[ next_edl_array_index ].stop_sec = stop;
+	 }
+	 next_edl_array_index++;
+	 if( next_edl_array_index >= MAX_EDL_ENTRIES-1 ) {
+	   break;
 	 }
        }
        if( next_edl_array_index > 0 ) {
@@ -998,7 +1106,7 @@
    printf( "EDL Records:\n" );
    if( next_edl_record->next != NULL ) {
      while( next_edl_record->next != NULL ) {
-       printf( "EDL: start [%f], stop [%f], action [%d]\n", next_edl_record->start_sec, next_edl_record->stop_sec, next_edl_record->action );
+       printf( "EDL: chapter [%d], start [%f], stop [%f], action [%d]\n", next_edl_record->chapter, next_edl_record->start_sec, next_edl_record->stop_sec, next_edl_record->action );
        next_edl_record = next_edl_record->next;
      }
      next_edl_record = edl_records;
@@ -1007,7 +1115,6 @@
 #endif
  }
 #endif
-
     if(!filename){
       if(!use_gui){
 	// no file/vcd/dvd -> show HELP:
@@ -2393,7 +2500,18 @@
 
 #ifdef USE_EDL
  if( next_edl_record->next ) { // Are we (still?) doing EDL?
+#ifdef USE_DVDREAD
+   dvd_priv_t* dvdp = stream->priv;
+   if( ( ( stream->type == STREAMTYPE_DVD ) && 
+       ( ( ( next_edl_record->chapter == -1 ) || 
+	   ( ( dvd_chapter_from_cell( dvdp, 0, dvdp->cur_cell ) + 1 ) ==
+	   next_edl_record->chapter ) ) &&
+	 sh_video->pts >= next_edl_record->start_sec ) ) ||
+       ( stream->type != STREAMTYPE_DVD && 
+	 sh_video->pts >= next_edl_record->start_sec ) ) {
+#else
    if( sh_video->pts >= next_edl_record->start_sec ) {
+#endif
      if( next_edl_record->action == EDL_SKIP ) {
        osd_function = OSD_FFW;
        abs_seek_pos = 0;
@@ -2404,7 +2522,7 @@
        edl_decision = 1;
        next_edl_record = next_edl_record->next;
      } else if( next_edl_record->action == EDL_MUTE ) {
-       mixer_mute();
+       toggleMute( EDL_MUTE_REQUESTOR );
 #ifdef DEBUG_EDL
        printf( "\nEDL_MUTE: [%f]\n", next_edl_record->start_sec );
 #endif
@@ -2452,7 +2570,17 @@
     case MP_CMD_EDL_MARK:
       if( edl_fd ) {
 	float v = sh_video->pts;
+#ifdef USE_DVDREAD
+	if( stream->type == STREAMTYPE_DVD ) {
+	  dvd_priv_t* dvdp = stream->priv;
+	  int chapter = ( dvd_chapter_from_cell( dvdp, 0, dvdp->cur_cell ) + 1 );
+	  fprintf( edl_fd, "%d %f %f %d\n", chapter, v-2, v, 0 );	  
+	} else {
+	  fprintf( edl_fd, "%f %f %d\n", v-2, v, 0 );
+	}
+#else
 	fprintf( edl_fd, "%f %f %d\n", v-2, v, 0 );
+#endif
       }
       break;
 #endif
@@ -2580,7 +2708,11 @@
 #endif
     } break;
     case MP_CMD_MUTE:
+#ifdef USE_EDL
+      toggleMute( USER_MUTE_REQUESTOR );
+#else
       mixer_mute();
+#endif
       break;
     case MP_CMD_LOADFILE : {
       play_tree_t* e = play_tree_new();
@@ -3256,12 +3388,42 @@
       }
   }
 #ifdef USE_EDL
+      // These #define's are ordered from the fastest to the slowest
+      // to execute; order them in the logic accordingly.
+#define EDL_IS_MUTE ( edl_records[ x ].action == EDL_MUTE )
+#define EDL_GLOBAL_CHAPTER ( edl_records[ x ].chapter == -1 )
+#define EDL_IS_DVD ( stream->type == STREAMTYPE_DVD )
+#define EDL_PAST_CURRENT_TIME ( edl_records[ x ].start_sec >= sh_video->pts )
+#define EDL_PAST_CURRENT_CHAPTER ( edl_records[ x ].chapter >= ( dvd_chapter_from_cell( dvdp, 0, dvdp->cur_cell ) + 1 ) )
       {
 	int x;
 	if( !edl_decision ) {
+	  // Reset EDL muted status
+	  // TODO: Traverse EDL records to determine proper mute
+	  // status
+	  toggleMute( SKIP_MUTE_REQUESTOR );
+
 	  for( x = 0; x < num_edl_records; x++ ) { // FIXME: do binary search
-	    // Find first EDL entry where start follows current time
-	    if( edl_records[ x ].start_sec >= sh_video->pts && edl_records[ x ].action != EDL_MUTE ) {
+	    // Find first EDL entry where start follows current time;
+	    // we want the next EDL record to be in the future.
+#ifdef USE_DVDREAD
+	    dvd_priv_t* dvdp = stream->priv;
+	    
+	    // If the record in question is a mute record, then skip
+	    // to next;
+	    // If the record in question is not past the current time,
+	    // then skip to next;
+	    // If the stream is not a DVD, we do not care about the
+	    // chapter info;
+	    // If we either have a global chapter setting or if the
+	    // current chapter is past (or equal to) the EDL record
+	    // chapter, set this EDL record to the current one.
+	    if( ( !EDL_IS_MUTE && 
+		  ( !EDL_IS_DVD || ( !EDL_GLOBAL_CHAPTER && EDL_PAST_CURRENT_CHAPTER ) ) && 
+		  EDL_PAST_CURRENT_TIME ) ) {
+#else
+	    if( !EDL_IS_MUTE && EDL_PAST_CURRENT_TIME ) {
+#endif // USE_DVDREAD
 	      next_edl_record = &edl_records[ x ];
 	      break;
 	    }
@@ -3270,7 +3432,7 @@
 	  edl_decision = 0;
 	}
       }
-#endif
+#endif // USE_EDL
   rel_seek_secs=0;
   abs_seek_pos=0;
   frame_time_remaining=0;
Index: DOCS/en/documentation.html
===================================================================
RCS file: /cvsroot/mplayer/main/DOCS/en/documentation.html,v
retrieving revision 1.416
diff -u -r1.416 documentation.html
--- DOCS/en/documentation.html	24 Jul 2003 06:49:59 -0000	1.416
+++ DOCS/en/documentation.html	26 Jul 2003 02:03:43 -0000
@@ -1292,7 +1292,7 @@
 
 <H3><A NAME="edl_making">2.5.2 Making an EDL file</A></H3>
 
-<P>The current EDL file format is:</P>
+<P>The original EDL file format is:</P>
 
 <CODE>[begin second] [end second] [action]</CODE>
 
@@ -1309,12 +1309,34 @@
   15 seconds, unmute at 16.7 seconds and skip from second 420 to second
   422 of the video. These actions will be performed when the playback timer
   reaches the times given in the file.</P>
+
+<P>Most DVD streams contain chapters. MPlayer's timer resets to 0 at
+the start of each chapter, and so just having seconds denote the
+location is insufficient in these cases. The modified EDL file format
+for DVD streams is:</P>
+
+<CODE>[chapter] [begin second] [end second] [action]</CODE>
+
+<P>When playing a DVD stream with an EDL, the EDL file would look
+something like this:</P>
+
+<PRE>
+3    5.3   7.1    0
+11   15    16.7   1
+11   42    44     0
+</PRE>
+
+<P>The first number in each line is the chapter number to which the
+following start second, stop second, and action all apply. When
+using an EDL with a DVD stream, this format should be used.</P>
   
 <P>To create an EDL file to work from, use the
   <CODE>-edlout &lt;filename&gt;</CODE> flag. During playback, when you want to
   mark the previous two seconds to skip over, hit <CODE>i</CODE>. A
-  corresponding entry will be written to the file for that time. You can then go
-  back and fine-tune the generated EDL file.</P>
+  corresponding entry will be written to the file for that time. The
+  format of the entry will depend on whether or not you are playing a
+  DVD stream. You can then go back and fine-tune the generated EDL
+  file.</P>
   
 
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20030725/e85d00f9/attachment.pgp>


More information about the MPlayer-dev-eng mailing list