[MPlayer-dev-eng] [PATCH] EDL 0.6 - DVD chapter support

Michael Halcrow mike at halcrow.us
Thu Jul 24 23:33:48 CEST 2003


Attached is a patch for EDL 0.6.  sh_video->pts resets at the start of
every chapter for some DVD's.  For example, it doesn't for Emma, and
it does for Life is Beautiful.  For DVD's where sh_video->pts resets
at the start of each chapter, EDL breaks.  This patch allows you to
optionally include chapters along with the timecodes for these DVD's.
This patch does not break backwards compatibility; any old EDL files
will still work fine.

I also modified the muting mechanism to be somewhat intelligent when
you seek, so that EDL does not override the user's muting requests,
and it recovers gracefully from manual seeks during playback.

This includes a bugfix.  Please include this with version 0.91, if
possible.

Thanks,
Mike

-- 
------------------------------------------- | ---------------------
Michael Halcrow                             | mike at halcrow.us     
Developer, IBM Linux Technology Center      |                      
                                            |
Give a man a fish, he owes you one fish.    |
Teach a man to fish, you give up your       |
monopoly on fisheries.                      |
------------------------------------------- | ---------------------
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 -r1.2 edl.h
1c1
< // EDL version 0.5
---
> // EDL version 0.6
17a18
>   int chapter;
Index: mplayer.c
===================================================================
RCS file: /cvsroot/mplayer/main/mplayer.c,v
retrieving revision 1.708
diff -r1.708 mplayer.c
344a345,405
> 
> 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;
>     } else if( muteRequestor == USER_MUTE_REQUESTOR ) {
>       mute_state = MUTED_BY_USER_ONLY;
>     } else if( muteRequestor == SKIP_MUTE_REQUESTOR ) {
>       // Do nothing; we're good
>     }
>     mixer_mute();
>     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;
>   }
> }
> 
914a976,980
> 
> #ifndef MAX_EDL_LINE_LENGTH
> #define MAX_EDL_LINE_LENGTH 100
> #endif
> 
917c983
<    char line[ 100 ];
---
>    char line[ MAX_EDL_LINE_LENGTH ];
919c985
<    int action;
---
>    int chapter, action;
928c994,997
<        while( fgets( line, 99, fd ) != NULL ) {
---
>        while( fgets( line, ( MAX_EDL_LINE_LENGTH - 1 ), fd ) != NULL ) {
> 	 int tokenIdx = 0;
> 	 char* token;
> 	 float vals[ 4 ];
930,939c999,1008
< 	 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;
941c1010,1035
< 	   if( stop <= start ) {
---
> 	   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
> 	   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( start <= edl_records[ next_edl_array_index-1 ].stop_sec ) {
943c1037
< 	     printf( "Stop time must follow start time. Discarding EDL entry.\n" );
---
> 	     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 );
946,964c1040,1051
< 	   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" );
> 	   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;
968a1056,1069
> 	   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;
1001c1102
<        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 );
1010d1110
< 
2395a2496,2505
> #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
2396a2507
> #endif
2407c2518
<        mixer_mute();
---
>        toggleMute( EDL_MUTE_REQUESTOR );
2454a2566,2574
> #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
2455a2576
> #endif
2582a2704,2706
> #ifdef USE_EDL
>       toggleMute( USER_MUTE_REQUESTOR );
> #else
2583a2708
> #endif
3258a3384,3390
>       // 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 ( ( dvd_chapter_from_cell( dvdp, 0, dvdp->cur_cell ) + 1 ) >= edl_records[ x ].chapter )
3261a3394,3398
> 	  // Reset EDL muted status
> 	  // TODO: Traverse EDL records to determine proper mute
> 	  // status
> 	  toggleMute( SKIP_MUTE_REQUESTOR );
> 
3263,3264c3400,3420
< 	    // 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
> 	      printf( "\nSelecting [%f]\n", edl_records[ x ].start_sec );
3273c3429
< #endif
---
> #endif // USE_EDL
-------------- 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/20030724/a8c4f268/attachment.pgp>


More information about the MPlayer-dev-eng mailing list