[MPlayer-dev-eng] [PATCH] EDL for MEncoder

Oded Shimon ods15 at ods15.dyndns.org
Sat Mar 19 19:05:53 CET 2005


On Mon, Mar 14, 2005 at 12:38:21AM +0200, Oded Shimon wrote:
> On Saturday 12 March 2005 23:47, Oded Shimon wrote:
> > On Friday 25 February 2005 07:36, Oded Shimon wrote:
> > > My EDL for MEncoder is now complete and ready, now that its dependency
> > >  patches have been committed.
> > > EDL mute for now does absolutely nothing. I find this a toy feature
> > > anyway. It can be added later, I have already made the EDL parsing for
> > > it, all what is missing is some kind of muting implementation. This is
> > > completely impossible with -oac copy.
> > >
> > > Compiled and tested...
> 
> Had a float/int mistake, cause skipped frames. fixed in this patch.

OK, finally patch done. It now has '-hr-edl-seek', which makes seeking done by
dropping frames instead of demux_seek. It will fail miserably in broken
demuxers with -ovc copy, because it waits for a keyframe and I know at least
the MPG demuxer never reports keyframes (hence it'll just keep dumping frames
till end of file). Also, edl_mute still does nothing.

- ods15
-------------- next part --------------
Index: cfg-common.h
===================================================================
RCS file: /cvsroot/mplayer/main/cfg-common.h,v
retrieving revision 1.139
diff -u -r1.139 cfg-common.h
--- cfg-common.h	24 Feb 2005 15:00:47 -0000	1.139
+++ cfg-common.h	19 Mar 2005 17:56:25 -0000
@@ -74,6 +74,11 @@
 	{"sb", &seek_to_byte, CONF_TYPE_POSITION, CONF_MIN, 0, 0, NULL},
 	{"ss", &seek_to_sec, CONF_TYPE_STRING, CONF_MIN, 0, 0, NULL},
 
+#ifdef USE_EDL
+	{"edl", &edl_filename,  CONF_TYPE_STRING, 0, 0, 0, NULL},
+#else
+	{"edl", "MPlayer was compiled without EDL support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
+#endif
 	// AVI specific: force non-interleaved mode
 	{"ni", &force_ni, CONF_TYPE_FLAG, 0, 0, 1, NULL},
 	{"noni", &force_ni, CONF_TYPE_FLAG, 0, 1, 0, NULL},
Index: cfg-mencoder.h
===================================================================
RCS file: /cvsroot/mplayer/main/cfg-mencoder.h,v
retrieving revision 1.93
diff -u -r1.93 cfg-mencoder.h
--- cfg-mencoder.h	25 Feb 2005 02:32:29 -0000	1.93
+++ cfg-mencoder.h	19 Mar 2005 17:56:25 -0000
@@ -200,6 +200,11 @@
 
 	{"endpos", &end_at_string, CONF_TYPE_STRING, 0, 0, 0, NULL},
 
+#ifdef USE_EDL
+        {"hr-edl-seek", &edl_seek_type, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+        {"nohr-edl-seek", &edl_seek_type, CONF_TYPE_FLAG, 0, 1, 0, NULL},
+#endif
+
 	// set output framerate - recommended for variable-FPS (ASF etc) files
 	// and for 29.97FPS progressive MPEG2 streams
 	{"ofps", &force_ofps, CONF_TYPE_FLOAT, CONF_MIN|CONF_GLOBAL, 0, 0, NULL},
Index: cfg-mplayer.h
===================================================================
RCS file: /cvsroot/mplayer/main/cfg-mplayer.h,v
retrieving revision 1.244
diff -u -r1.244 cfg-mplayer.h
--- cfg-mplayer.h	1 Mar 2005 03:51:48 -0000	1.244
+++ cfg-mplayer.h	19 Mar 2005 17:56:25 -0000
@@ -172,10 +172,8 @@
 	{"noalsa", "-noalsa has been removed. Remove it from your config file.\n",
             CONF_TYPE_PRINT, 0, 0, 0, NULL},
 #ifdef USE_EDL
-	{"edl", &edl_filename,  CONF_TYPE_STRING, 0, 0, 0, NULL}, 
 	{"edlout", &edl_output_filename,  CONF_TYPE_STRING, 0, 0, 0, NULL}, 
 #else
-	{"edl", "MPlayer was compiled without EDL support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
 	{"edlout", "MPlayer was compiled without EDL support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
 #endif
 
Index: mencoder.c
===================================================================
RCS file: /cvsroot/mplayer/main/mencoder.c,v
retrieving revision 1.271
diff -u -r1.271 mencoder.c
--- mencoder.c	1 Mar 2005 20:21:58 -0000	1.271
+++ mencoder.c	19 Mar 2005 17:56:27 -0000
@@ -270,6 +270,20 @@
 
 #include "get_path.c"
 
+#ifdef USE_EDL
+#include "edl.h"
+static edl_record_ptr edl_records = NULL; ///< EDL entries memory area
+static edl_record_ptr next_edl_record = NULL; ///< only for traversing edl_records
+static short edl_muted; ///< Stores whether EDL is currently in muted mode.
+static short edl_seeking; ///< When non-zero, stream is seekable.
+static short edl_seek_type; ///< When non-zero, frames are discarded instead of seeking.
+static short edl_skip; ///< -1 OR the value of in_size of an already read frame.
+/** \brief Seeks for EDL
+    \return 1 for success, 0 for failure, 2 for EOF.
+*/
+int edl_seek(edl_record_ptr next_edl_record, demuxer_t* demuxer, demux_stream_t *d_audio, muxer_stream_t* mux_a, float * frame_time, unsigned char ** start, int framecopy);
+#endif
+
 #include "cfg-mplayer-def.h"
 #include "cfg-mencoder.h"
 
@@ -1295,6 +1309,16 @@
 play_n_frames=play_n_frames_mf;
 if (curfile && end_at_type == END_AT_TIME) end_at += mux_v->timer;
 
+#ifdef USE_EDL
+if (edl_filename) {
+    if (edl_records) free_edl(edl_records);
+    next_edl_record = edl_records = edl_parse_file();
+    edl_muted = 0;
+    edl_seeking = 1;
+    edl_skip = -1;
+}
+#endif
+
 while(!at_eof){
 
     float frame_time=0;
@@ -1314,6 +1338,47 @@
       if(play_n_frames<0) break;
     }
 
+#ifdef USE_EDL
+goto_redo_edl:
+    if (next_edl_record && sh_video && sh_video->pts >= next_edl_record->start_sec) {
+        if (next_edl_record->action == EDL_SKIP && edl_seeking) {
+            float last_pos = d_video->pts;
+            int result;
+            mp_msg(MSGT_CPLAYER, MSGL_DBG4, "EDL_SKIP: start [%f], stop [%f], length [%f]\n",
+                   next_edl_record->start_sec, next_edl_record->stop_sec, next_edl_record->length_sec);
+
+            result = edl_seek(next_edl_record, demuxer, d_audio, mux_a, &frame_time, &start, mux_v->codec==VCODEC_COPY);
+
+            if (result == 2) break; // EOF
+            else if (result == 0) edl_seeking = 0; // no seeking
+            else { // sucess
+                edl_muted = 0;
+                if (last_pos >= sh_video->pts) {
+                    // backwards seek detected!! Forget about this EDL skip altogether.
+                    next_edl_record = next_edl_record->next;
+                }
+                else for (next_edl_record = edl_records; next_edl_record; next_edl_record = next_edl_record->next) {
+                    /* note the use of stop_sec,
+                       meaning if by some magical way we landed in the MIDDLE of a censored area,
+                       in the next loop it will jump out of it.
+                    */
+                    if (next_edl_record->stop_sec > sh_video->pts) break; // we got to the right place.
+                    if (next_edl_record->action == EDL_MUTE) edl_muted = !edl_muted; // toggle mute each time.
+                }
+
+                /* for a pedantic EDL, that doesn't show even a single
+                   frame from the "censored" area, uncomment next line. */
+                goto goto_redo_edl;
+            }
+        } else if (next_edl_record->action == EDL_MUTE) {
+            edl_muted = !edl_muted;  // This variable does nothing for now.
+            mp_msg(MSGT_CPLAYER, MSGL_DBG4, "EDL_MUTE: [%f]\n", next_edl_record->start_sec );
+            next_edl_record=next_edl_record->next;
+        }
+    }
+#endif
+
+
 if(sh_audio){
     // get audio:
     while(mux_a->timer-audio_preload<mux_v->timer){
@@ -1470,6 +1535,10 @@
 
     // get video frame!
 
+#ifdef USE_EDL
+    if (edl_skip != -1) { in_size = edl_skip; edl_skip = -1; }
+    else
+#endif
     in_size=video_read_frame(sh_video,&frame_time,&start,force_fps);
     if(in_size<0){ at_eof=1; break; }
     sh_video->timer+=frame_time; ++decoded_frameno;
@@ -2025,9 +2094,93 @@
 #endif
 
 static float stop_time(demuxer_t* demuxer, muxer_stream_t* mux_v) {
-	// demuxer is for future support for EDL
 	float timeleft = -1;
 	if (play_n_frames >= 0) timeleft = mux_v->timer + play_n_frames * (double)(mux_v->h.dwScale) / mux_v->h.dwRate;
 	if (end_at_type == END_AT_TIME && (timeleft > end_at || timeleft == -1)) timeleft = end_at;
+#ifdef USE_EDL
+	if (next_edl_record && demuxer && demuxer->video) { // everything is OK to be checked
+		float tmp = mux_v->timer + next_edl_record->start_sec - demuxer->video->pts;
+		if (timeleft == -1 || timeleft > tmp) {
+			// There's less time in EDL than what we already know
+			if (next_edl_record->action == EDL_SKIP && edl_seeking) {
+				timeleft = tmp;
+			} else if (next_edl_record->action == EDL_MUTE) {
+				//timeleft = next_edl_record->start_sec - demuxer->video->pts;
+				// For the moment (and probably forever) EDL mute doesn't work in MEncoder
+			}
+		}
+	}
+#endif
 	return timeleft;
 }
+
+#ifdef USE_EDL
+int edl_seek(edl_record_ptr next_edl_record, demuxer_t* demuxer, demux_stream_t *d_audio, muxer_stream_t* mux_a, float * frame_time, unsigned char ** start, int framecopy) {
+    sh_audio_t * sh_audio = d_audio->sh;
+    sh_video_t * sh_video = demuxer->video ? demuxer->video->sh : NULL;
+    int softskip = 0;
+    vf_instance_t * vfilter = sh_video ? sh_video->vfilter : NULL;
+
+    if (!sh_video) return 0;
+    if (sh_video->pts >= next_edl_record->stop_sec) return 1; // nothing to do...
+
+    if (!edl_seek_type) {
+        if(demux_seek(demuxer, next_edl_record->stop_sec - sh_video->pts, 0)){
+            sh_video->pts = demuxer->video->pts;
+            //if (vo_vobsub) vobsub_seek(vo_vobsub,sh_video->pts);
+            resync_video_stream(sh_video);
+            //if(vo_spudec) spudec_reset(vo_spudec);
+            return 1;
+        }
+        // non-seekable stream.
+        return 0;
+    }
+
+    // slow seek, read every frame.
+
+    if (vfilter && vfilter->control(vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) == CONTROL_TRUE) softskip = 1;
+
+    while (!interrupted) {
+        float a_pts = 0.;
+        int in_size;
+
+        in_size = video_read_frame(sh_video, frame_time, start, force_fps);
+        if(in_size<0) return 2;
+        sh_video->timer += *frame_time;
+
+        if (sh_audio) {
+            a_pts = d_audio->pts + (ds_tell_pts(d_audio) - sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+            while (sh_video->pts > a_pts) {
+                if (mux_a->h.dwSampleSize) {
+                    int len;
+                    len = mux_a->wf->nAvgBytesPerSec * (sh_video->pts - a_pts);
+                    len/= mux_a->h.dwSampleSize; if(len<1) len=1;
+                    len*= mux_a->h.dwSampleSize;
+                    demux_read_data(sh_audio->ds,mux_a->buffer,len);
+                } else {
+                    ds_get_packet(sh_audio->ds,(unsigned char**) &mux_a->buffer);
+                }
+                a_pts = d_audio->pts + (ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+            }
+        }
+
+        if (sh_video->pts >= next_edl_record->stop_sec) {
+            if (!framecopy) return 1;
+            else if (sh_video->ds->flags & 1) {
+                edl_skip = in_size;
+                return 1;
+            }
+        }
+
+        if (softskip) vfilter->control(vfilter, VFCTRL_SKIP_NEXT_FRAME, 0);
+        if (vfilter) decode_video(sh_video, *start, in_size, !softskip);
+
+        mp_msg(MSGT_MENCODER, MSGL_STATUS,
+               "EDL SKIP: Start: %.2f  End: %.2lf   Current: V: %.2f  A: %.2f     \r",
+               next_edl_record->start_sec, next_edl_record->stop_sec,
+               sh_video->pts, a_pts);
+    }
+    if (interrupted) return 2;
+    return 1;
+}
+#endif


More information about the MPlayer-dev-eng mailing list