mirror of https://github.com/mpv-player/mpv
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
This commit is contained in:
parent
020f569cc1
commit
afdca81f8f
2
Makefile
2
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
|
||||
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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
|
15
edl.h
15
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
|
||||
|
|
222
mplayer.c
222
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;
|
||||
|
|
Loading…
Reference in New Issue