From afdca81f8f6a33b491f56494c35983de97a2ebea Mon Sep 17 00:00:00 2001 From: rtognimp Date: Sat, 28 Aug 2004 00:46:05 +0000 Subject: [PATCH] EDL enhancement/fixes: *Some edl's code moved from mplayer.c to edl.c (mencoder will use the same functions) * slighty faster * removed MAX_EDL_ENTRIES limit (just reserve the memory we really need) * really treat edl_records as a linked list (coz it is) * edl now 'remembers' pending operations after a manual _seek_ * better way of handling Mute/Umute eliminates some nasty bugs when manual seeking (scrwed up mute/unmute order, no audio after seek, etc) * seeking while on -edl mode now _WORKS_ Patch by Reynaldo H. Verdejo Pinochet (reynaldo at opendot dot cl) git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@13169 b3059339-0415-0410-9bf9-f77b7e298cf2 --- Makefile | 2 +- edl.c | 161 +++++++++++++++++++++++++++++++++++++++ edl.h | 15 +++- mplayer.c | 222 +++++++++++++++++++++++++----------------------------- 4 files changed, 278 insertions(+), 122 deletions(-) create mode 100644 edl.c diff --git a/Makefile b/Makefile index 5ace327b29..869bbd528d 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ SUBDIRS += libdha vidix DO_MAKE = @ for i in $(SUBDIRS); do $(MAKE) -C $$i $@; done endif -SRCS_COMMON = cpudetect.c codec-cfg.c spudec.c playtree.c playtreeparser.c asxparser.c vobsub.c subreader.c sub_cc.c find_sub.c m_config.c m_option.c parser-cfg.c m_struct.c +SRCS_COMMON = cpudetect.c codec-cfg.c spudec.c playtree.c playtreeparser.c asxparser.c vobsub.c subreader.c sub_cc.c find_sub.c m_config.c m_option.c parser-cfg.c m_struct.c edl.c SRCS_MENCODER = mencoder.c mp_msg-mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/osd.c libvo/sub.c libvo/font_load.c libvo/font_load_ft.c xvid_vbr.c parser-mecmd.c SRCS_MPLAYER = mplayer.c mp_msg.c $(SRCS_COMMON) mixer.c parser-mpcmd.c diff --git a/edl.c b/edl.c new file mode 100644 index 0000000000..78360bf4f6 --- /dev/null +++ b/edl.c @@ -0,0 +1,161 @@ +#include +#include +#include "config.h" +#include "mp_msg.h" +#include "edl.h" + +#ifdef USE_EDL + +int edl_check_mode(void) +{ + if (edl_filename && edl_output_filename) + { + return (EDL_ERROR); + } + + return (1); +} + +int edl_count_entries(void) +{ + FILE *fd = NULL; + int entries = 0; + int action = 0; + float start = 0; + float stop = 0; + char line[100]; + + if (edl_filename) + { + if ((fd = fopen(edl_filename, "r")) == NULL) + { + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Invalid EDL file, cant open '%s' for reading!\n", + edl_filename); + return (EDL_ERROR); + } else + { + while (fgets(line, 99, fd) != NULL) + { + if ((sscanf(line, "%f %f %d", &start, &stop, &action)) == + 3) + { + if (action == EDL_SKIP) + entries += 1; + if (action == EDL_MUTE) + entries += 2; + } else + { + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Invalid EDL line: %s\n", line); + return (EDL_ERROR); + } + + } + } + } else + { + return (EDL_ERROR); + } + + return (entries); +} + +int edl_parse_file(edl_record_ptr edl_records) +{ + FILE *fd; + char line[100]; + float start, stop; + int action; + int record_count = 0; + int lineCount = 0; + struct edl_record *next_edl_record = edl_records; + + if (edl_filename) + { + if ((fd = fopen(edl_filename, "r")) == NULL) + { + return (EDL_ERROR); + } else + { + while (fgets(line, 99, fd) != NULL) + { + lineCount++; + if ((sscanf(line, "%f %f %d", &start, &stop, &action)) + != 3) + { + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Badly formated EDL line [%d]. Discarding!\n", + lineCount + 1, line); + continue; + } else + { + if (record_count > 0) + { + if (start <= (next_edl_record - 1)->stop_sec) + { + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Invalid EDL line [%d]: %s", + lineCount, line); + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Last stop position was [%f]; next start is [%f]. Entries must be in chronological order and cannot overlap. Discarding!\n", + (next_edl_record - 1)->stop_sec, start); + continue; + } + } + if (stop <= start) + { + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Invalid EDL line [%d]: %s", lineCount, + line); + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Stop time must follow start time. Discarding!\n"); + continue; + } + next_edl_record->action = action; + if (action == EDL_MUTE) + { + next_edl_record->length_sec = 0; + next_edl_record->start_sec = start; + next_edl_record->stop_sec = start; + next_edl_record->mute_state = EDL_MUTE_START; + next_edl_record++; + (next_edl_record - 1)->next = next_edl_record; + next_edl_record->action = action; + next_edl_record->length_sec = 0; + next_edl_record->start_sec = stop; + next_edl_record->stop_sec = stop; + next_edl_record->mute_state = EDL_MUTE_END; + + } else + { + next_edl_record->length_sec = stop - start; + next_edl_record->start_sec = start; + next_edl_record->stop_sec = stop; + } + next_edl_record++; + + if (record_count >= 0) + { + (next_edl_record - 1)->next = next_edl_record; + } + + record_count++; + } + } + + if (record_count > 0) + { + (next_edl_record - 1)->next = NULL; + } + } + fclose(fd); + } else + { + return (EDL_ERROR); + } + + return (record_count); +} + +#endif diff --git a/edl.h b/edl.h index 07fd2e71de..1bc8e58159 100644 --- a/edl.h +++ b/edl.h @@ -1,12 +1,13 @@ -// EDL version 0.5 +// EDL version 0.6 #ifndef EDLH #define EDLH #define EDL_SKIP 0 #define EDL_MUTE 1 - -#define MAX_EDL_ENTRIES 1000 +#define EDL_ERROR -1 +#define EDL_MUTE_START 1 +#define EDL_MUTE_END 0 struct edl_record { float start_sec; @@ -16,9 +17,17 @@ struct edl_record { float length_sec; long length_frame; short action; + short mute_state; struct edl_record* next; }; typedef struct edl_record* edl_record_ptr; +char *edl_filename; // file to extract edl entries from (-edl) +char *edl_output_filename; // file to put edl entries in (-edlout) + +int edl_check_mode(void); // we cannot do -edl and -edlout at the same time +int edl_count_entries(void); // returns total No of entries needed +int edl_parse_file(edl_record_ptr edl_records); // fills edl stack + #endif diff --git a/mplayer.c b/mplayer.c index fb293e74d4..de5023349f 100644 --- a/mplayer.c +++ b/mplayer.c @@ -349,13 +349,13 @@ static char* rtc_device; #endif #ifdef USE_EDL -struct edl_record edl_records[ MAX_EDL_ENTRIES ]; -int num_edl_records = 0; -FILE* edl_fd = NULL; -edl_record_ptr next_edl_record = NULL; -static char* edl_filename = NULL; -static char* edl_output_filename = NULL; -short edl_decision = 0; +edl_record_ptr edl_records = NULL; // EDL entries memory area +edl_record_ptr next_edl_record = NULL; // only for traversing edl_records +int edl_memory_slots = 0; // No of EDL entries (1 for skip + 2 for each mute) +int edl_operations = 0; // No of EDL operations, skip + mute +short edl_decision = 0; // 1 when an EDL operation has been made +FILE* edl_fd = NULL; // fd to write to when in -edlout mode +int edl_mute_count = 0; // even number when mute has been matched mute/unmute #endif static unsigned int inited_flags=0; @@ -959,100 +959,54 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){ #endif #ifdef USE_EDL - { - FILE* fd; - char line[ 100 ]; - float start, stop, duration; - int action; - int next_edl_array_index = 0; - int lineCount = 0; - next_edl_record = edl_records; - if( edl_filename ) { - if( ( fd = fopen( edl_filename, "r" ) ) == NULL ) { - printf( "Error opening EDL file [%s]!\n", edl_filename ); - next_edl_record->next = NULL; - } else { - while( fgets( line, 99, fd ) != NULL ) { - 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; - } - } - 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; - 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; - } - next_edl_array_index++; - if( next_edl_array_index >= MAX_EDL_ENTRIES-1 ) { - break; - } - } - } - if( next_edl_array_index > 0 ) { - edl_records[ next_edl_array_index-1 ].next = &edl_records[ next_edl_array_index ]; - } - edl_records[ next_edl_array_index ].start_sec = -1; - edl_records[ next_edl_array_index ].next = NULL; - num_edl_records = ( next_edl_array_index ); - } - fclose( fd ); - } else { - next_edl_record->next = NULL; - } - if( edl_output_filename ) { - if( edl_filename ) { - printf( "Sorry; EDL mode and EDL output mode are mutually exclusive! Disabling all EDL functions.\n" ); - edl_output_filename = NULL; - edl_filename = NULL; - next_edl_record->next = NULL; - } else { - if( ( edl_fd = fopen( edl_output_filename, "w" ) ) == NULL ) { - printf( "Error opening file [%s] for writing!\n", edl_output_filename ); - edl_output_filename = NULL; - next_edl_record->next = NULL; - } - } - } -#ifdef DEBUG_EDL - { - 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 ); - next_edl_record = next_edl_record->next; - } - next_edl_record = edl_records; - } - } -#endif - } +if (edl_check_mode() == EDL_ERROR && edl_filename) +{ + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Cant use -edl and -edlout at the same time\n"); + mp_msg(MSGT_CPLAYER, MSGL_WARN, "Not using EDL at all!!!\n"); + edl_filename = NULL; + edl_output_filename = NULL; + edl_records = NULL; + next_edl_record = edl_records; +} else if (edl_filename) +{ + edl_memory_slots = edl_count_entries(); + if (edl_memory_slots > 0) + { + edl_records = calloc(edl_memory_slots, sizeof(struct edl_record)); + if (edl_records == NULL) + { + mp_msg(MSGT_CPLAYER, MSGL_FATAL, + "Cant allocate enough memory to hold EDL data, exiting!\n"); + exit_player(NULL); + } else + { + if ((edl_operations = edl_parse_file(edl_records)) > 0) + { + mp_msg(MSGT_CPLAYER, MSGL_INFO, "Readed %d EDL actions\n", + edl_operations); + } else + { + + mp_msg(MSGT_CPLAYER, MSGL_INFO, + "There are no EDL actions to take care of\n"); + } + } + } + + next_edl_record = edl_records; + +} else if (edl_output_filename) +{ + if ((edl_fd = fopen(edl_output_filename, "w")) == NULL) + { + mp_msg(MSGT_CPLAYER, MSGL_WARN, + "Error opening file [%s] for writing!\n", + edl_output_filename); + edl_output_filename = NULL; + next_edl_record = edl_records; + } +} #endif if(!filename){ @@ -2493,7 +2447,7 @@ if (stream->type==STREAMTYPE_DVDNAV && dvd_nav_still) //================= EDL ========================================= #ifdef USE_EDL - if( next_edl_record->next ) { // Are we (still?) doing EDL? + if( next_edl_record ) { // Are we (still?) doing EDL? if ( !sh_video ) { mp_msg( MSGT_CPLAYER, MSGL_ERR, "Cannot use edit list without video. EDL disabled.\n" ); next_edl_record->next = NULL; @@ -2507,15 +2461,15 @@ if (stream->type==STREAMTYPE_DVDNAV && dvd_nav_still) printf( "\nEDL_SKIP: start [%f], stop [%f], length [%f]\n", next_edl_record->start_sec, next_edl_record->stop_sec, next_edl_record->length_sec ); #endif edl_decision = 1; - next_edl_record = next_edl_record->next; } else if( next_edl_record->action == EDL_MUTE ) { mixer_mute(&mixer); + edl_mute_count++; // new edl seek behavior need this #ifdef DEBUG_EDL printf( "\nEDL_MUTE: [%f]\n", next_edl_record->start_sec ); #endif edl_decision = 1; - next_edl_record = next_edl_record->next; } + next_edl_record=next_edl_record->next; } } } @@ -3548,20 +3502,52 @@ if(rel_seek_secs || abs_seek_pos){ } } #ifdef USE_EDL - { - int x; - if( !edl_decision ) { - 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 ) { - next_edl_record = &edl_records[ x ]; - break; - } - } - } else { - edl_decision = 0; - } - } +/* + * We Saw a seek, have to rewind the edl operations stak + * and find the next edl action to take care off + */ + +next_edl_record = edl_records; + +while (next_edl_record) +{ + /* trying to remember if we need to mute/unmute first + * prior edl implementation lacks this + */ + + if (next_edl_record->start_sec >= sh_video->pts) + { + if (edl_mute_count > 0) + { + if ((edl_mute_count % 2) == 0 && + next_edl_record->mute_state == EDL_MUTE_END) + { + mixer_mute(&mixer); + edl_mute_count++; + } + if ((edl_mute_count % 2) != 0 && + next_edl_record->mute_state == EDL_MUTE_START) + { + mixer_mute(&mixer); + edl_mute_count++; + } + } else if (next_edl_record->mute_state == EDL_MUTE_END) + { + mixer_mute(&mixer); + edl_mute_count++; + } + break; + } + + next_edl_record = next_edl_record->next; + + if (!next_edl_record && (edl_mute_count % 2) != 0 + && edl_mute_count > 0) + { + mixer_mute(&mixer); + edl_mute_count++; + } +} #endif rel_seek_secs=0; abs_seek_pos=0;