diff -uNbr main/cfg-mencoder.h main.new/cfg-mencoder.h --- main/cfg-mencoder.h Wed May 19 06:33:00 2004 +++ main.new/cfg-mencoder.h Tue Aug 24 10:39:10 2004 @@ -173,6 +173,9 @@ {"endpos", parse_end_at, CONF_TYPE_FUNC_PARAM, 0, 0, 0, NULL}, + {"fromclosestkeyframe", parse_from_closest_keyframe, CONF_TYPE_FUNC_PARAM, 0, 0, 0, NULL}, + {"untilclosestkeyframe", parse_until_closest_keyframe, CONF_TYPE_FUNC_PARAM, 0, 0, 0, NULL}, + // 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, 0, 0, NULL}, diff -uNbr main/libmpdemux/demux_mpg.c main.new/libmpdemux/demux_mpg.c --- main/libmpdemux/demux_mpg.c Sat Aug 7 16:20:28 2004 +++ main.new/libmpdemux/demux_mpg.c Tue Aug 24 10:39:10 2004 @@ -13,6 +13,7 @@ #include "parse_es.h" #include "stheader.h" #include "mp3_hdr.h" +#include "mpeg_hdr.h" //#define MAX_PS_PACKETSIZE 2048 #define MAX_PS_PACKETSIZE (224*1024) @@ -352,13 +353,79 @@ extern void resync_audio_stream(sh_audio_t *sh_audio); extern void skip_audio_frame(sh_audio_t *sh_audio); -void demux_seek_mpg(demuxer_t *demuxer,float rel_seek_secs,int flags){ +void demux_seek_mpg(demuxer_t *demuxer,float rel_seek_secs,int flags) { demux_stream_t *d_audio=demuxer->audio; demux_stream_t *d_video=demuxer->video; sh_audio_t *sh_audio=d_audio->sh; sh_video_t *sh_video=d_video->sh; //================= seek in MPEG ========================== + + //printf("Seeking with flags equal to : %d\n",flags); + if (flags&4) { + long int seek_field = rel_seek_secs; + + if (!rel_seek_secs) return; + off_t newpos=(flags&1)?demuxer->movi_start:demuxer->filepos; + + //This shouldn't be needed but it shouldn't hurt either + if(!videobuffer) { + char* videobuffer=(char*)memalign(8,VIDEOBUFFER_SIZE); + } + if(!videobuffer){ + mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_ShMemAllocFail); + return; + } + + ds_fill_buffer(d_video); + if(sh_audio){ + ds_fill_buffer(d_audio); + resync_audio_stream(sh_audio); + } + long int frame_num=0; + + int time_multiplier = 2; + int time_index = 0; + + while(1){ + int i; + if(sh_audio && !d_audio->eof && d_video->pts && d_audio->pts){ + float a_pts=d_audio->pts; + a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps; + if(d_video->pts>a_pts){ + skip_audio_frame(sh_audio); // sync audio + continue; + } + } + i=sync_video_packet(d_video); +// printf("Video packet: %X\n",i); + + if ((i==0x1B3 || i==0x1B8) && (frame_num>=seek_field)) break; // found it! + if(i==0x100) { + frame_num++; +// printf("Frame: %d on %d\n",frame_num, seek_field); + } + + if(i==0x1B5) { + int start=videobuf_len+4; + //Maybe we have a full frame and we need to add a second field + if (!read_video_packet(d_video)) break; // EOF + + if ((videobuffer[start] & 0xf0) == 0x80) { +// printf("FULL FRAME :"); + if ((videobuffer[start+2] & 3) == 3) { + //printf(" YES\n"); + frame_num++; + } else { + //printf(" NO\n"); + } + } + } else + if (!i || !skip_video_packet(d_video)) break; // EOF? + + } + } else { + //================= seek in MPEG ========================== off_t newpos=(flags&1)?demuxer->movi_start:demuxer->filepos; if(flags&2){ @@ -407,6 +474,7 @@ if(i==0x1B3 || i==0x1B8) break; // found it! if(!i || !skip_video_packet(d_video)) break; // EOF? } + } } int demux_mpg_control(demuxer_t *demuxer,int cmd, void *arg){ diff -uNbr main/libmpdemux/stheader.h main.new/libmpdemux/stheader.h --- main/libmpdemux/stheader.h Wed Apr 28 12:18:33 2004 +++ main.new/libmpdemux/stheader.h Tue Aug 24 10:39:10 2004 @@ -90,5 +90,6 @@ // video.c: int video_read_properties(sh_video_t *sh_video); int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps); +int video_read_frame2(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps,int *is_key_frame,int *is_full_frame); #endif diff -uNbr main/libmpdemux/video.c main.new/libmpdemux/video.c --- main/libmpdemux/video.c Sun Apr 11 21:03:12 2004 +++ main.new/libmpdemux/video.c Tue Aug 24 10:39:10 2004 @@ -309,7 +309,12 @@ printf("'\n"); } -int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps){ +int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps) { + int dummy,dummy2; + return video_read_frame2(sh_video,frame_time_ptr,start,force_fps,dummy,dummy2); +} + +int video_read_frame2(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps,int *is_key_frame,int *is_full_frame){ demux_stream_t *d_video=sh_video->ds; demuxer_t *demuxer=d_video->demuxer; float frame_time=1; @@ -318,8 +323,11 @@ int picture_coding_type=0; // unsigned char* start=NULL; int in_size=0; + int i; *start=NULL; + *is_key_frame = 0; + *is_full_frame = 0; if(demuxer->file_format==DEMUXER_TYPE_MPEG_ES || demuxer->file_format==DEMUXER_TYPE_MPEG_PS || demuxer->file_format==DEMUXER_TYPE_PVA || demuxer->file_format==DEMUXER_TYPE_MPEG_TS @@ -332,7 +340,7 @@ //float newfps; //videobuf_len=0; while(videobuf_lenfile_format==DEMUXER_TYPE_MPEG4_ES) || (demuxer->file_format==DEMUXER_TYPE_MPEG4_IN_TS)){ // while(videobuf_lenfile_format==DEMUXER_TYPE_H264_ES){ // while(videobuf_len0) { + int first_field = lroundf(from_closest_keyframe * sh_video->fps * 2); //2 times more fields than frames + printf("================ FROM field %d =============\n",first_field); + demux_seek(demuxer, first_field, 5); +} +if (until_closest_keyframe>0) { + last_field = lroundf(until_closest_keyframe * sh_video->fps * 2); //2 times more fields than frames + printf("================ FOR %d fields =============\n",last_field); +} + if (seek_to_sec) { int a,b; float d; @@ -1230,9 +1246,18 @@ } // get video frame! + int is_key_frame; + int is_full_frame; + in_size=video_read_frame2(sh_video,&frame_time,&start,force_fps,&is_key_frame,&is_full_frame); + cur_field++; + if (is_full_frame) + cur_field++; - in_size=video_read_frame(sh_video,&frame_time,&start,force_fps); if(in_size<0){ at_eof=1; break; } + + if((cur_field>=last_field) && is_key_frame) { + at_eof=1; break; + } sh_video->timer+=frame_time; ++decoded_frameno; v_timer_corr-=frame_time-(float)mux_v->h.dwScale/mux_v->h.dwRate; @@ -1530,6 +1555,34 @@ #endif return interrupted; +} + +static int parse_from_closest_keyframe(m_option_t *conf, const char* param) { + int a,b; + float d; + if (sscanf(param, "%d:%d:%f", &a, &b, &d) == 3) + from_closest_keyframe = 3600*a + 60*b + d; + else if (sscanf(param, "%d:%f", &a, &d) == 2) + from_closest_keyframe = 60*a + d; + else if (sscanf(param, "%f", &d) == 1) + from_closest_keyframe = d; + else + from_closest_keyframe = 0; + printf("\n============ SEEK FRAME %f =============\n",from_closest_keyframe); +} + +static int parse_until_closest_keyframe(m_option_t *conf, const char* param) { + int a,b; + float d; + if (sscanf(param, "%d:%d:%f", &a, &b, &d) == 3) + until_closest_keyframe = 3600*a + 60*b + d; + else if (sscanf(param, "%d:%f", &a, &d) == 2) + until_closest_keyframe = 60*a + d; + else if (sscanf(param, "%f", &d) == 1) + until_closest_keyframe = d; + else + until_closest_keyframe = 0; + printf("\n============ SEEK FRAME %f =============\n",from_closest_keyframe); } static int parse_end_at(m_option_t *conf, const char* param) diff -uNbr main/DOCS/man/en/mplayer.1 main.new/DOCS/man/en/mplayer.1 --- main/DOCS/man/en/mplayer.1 Tue Aug 24 01:24:27 2004 +++ main.new/DOCS/man/en/mplayer.1 Wed Aug 25 09:43:08 2004 @@ -4142,6 +4142,20 @@ .B \-audio-preload <0.0\-2.0> Sets up audio buffering time interval (default: 0.5s). .TP +.B \-fromclosestkeyframe <[[hh:]mm:]ss[.ms]> (see \-untilclosestkeyframe) +For MPEG2 files, start encoding at first GOP following given time or byte position. + +.I NOTE: +.br +Used in conjunction with untilclosestkeyframe, it should let you encode the file by +chunks and process it parallelly. +. +.TP +.B \-untilclosestkeyframe <[[hh:]mm:]ss[.ms]> (see \-untilclosestkeyframe) +For MPEG2 files, stop encoding after having encoded the given duration. The encoding +stops at the end of a GOP. +. +.TP .B \-endpos <[[hh:]mm:]ss[.ms]|size[b|kb|mb]> (see \-ss and \-sb option too) Stop encoding at given time or byte position. Can be specified in many ways: