--- mplayer/command.c.recorder~ 2010-04-06 13:16:58.000000000 +0200 +++ mplayer/command.c 2010-04-06 13:40:22.795706994 +0200 @@ -3006,6 +3006,26 @@ int run_command(MPContext * mpctx, mp_cm } break; + case MP_CMD_RECORD: + { + char *file=cmd->args[0].v.s; + int flags=0; + if(file) { + while(file[0]=='+' || file[0]=='%' || file[0]=='|' || file[0]=='@') { + if(file[0]=='+') + flags |= 1; /* append */ + else if(file[0]=='%') + flags |= 2; /* prepend */ + else if(file[0]=='|') + flags |= 4; /* pipe */ + else if(file[0]=='@') + flags |= 8; /* wait for data block (e.g. header) */ + file++; + } + } + recorder_switch(file, flags); + break; + } case MP_CMD_VF_CHANGE_RECTANGLE: if (!sh_video) break; --- mplayer/input/input.c.recorder~ 2010-04-06 13:40:22.785706791 +0200 +++ mplayer/input/input.c 2010-04-06 13:40:22.795706994 +0200 @@ -166,6 +166,7 @@ static const mp_cmd_t mp_cmds[] = { { MP_CMD_VO_ROOTWIN, "vo_rootwin", 0, { {MP_CMD_ARG_INT,{-1}}, {-1,{0}} } }, { MP_CMD_VO_BORDER, "vo_border", 0, { {MP_CMD_ARG_INT,{-1}}, {-1,{0}} } }, { MP_CMD_SCREENSHOT, "screenshot", 0, { {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, + { MP_CMD_RECORD, "record", 0, { {MP_CMD_ARG_STRING, {0}}, {-1,{0}} } }, { MP_CMD_PANSCAN, "panscan",1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, { MP_CMD_SWITCH_VSYNC, "switch_vsync", 0, { {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, { MP_CMD_LOADFILE, "loadfile", 1, { {MP_CMD_ARG_STRING, {0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, @@ -426,7 +427,7 @@ static const mp_cmd_bind_t def_cmd_binds { { '8', 0 }, "saturation 1" }, { { 'd', 0 }, "frame_drop" }, { { 'D', 0 }, "step_property deinterlace" }, - { { 'r', 0 }, "sub_pos -1" }, +// { { 'r', 0 }, "sub_pos -1" }, { { 't', 0 }, "sub_pos +1" }, { { 'a', 0 }, "sub_alignment" }, { { 'v', 0 }, "sub_visibility" }, @@ -473,6 +474,7 @@ static const mp_cmd_bind_t def_cmd_binds { { 'S', 0 }, "screenshot 1" }, { { 'w', 0 }, "panscan -0.1" }, { { 'e', 0 }, "panscan +0.1" }, + { { 'r', 0 }, "record" }, { { KEY_POWER, 0 }, "quit" }, { { KEY_MENU, 0 }, "osd" }, @@ -507,7 +509,8 @@ static const mp_cmd_bind_t gui_def_cmd_b { { KEY_ENTER, 0 }, "gui_play" }, { { KEY_ESC, 0 }, "gui_stop" }, { { 'p', 0 }, "gui_playlist" }, - { { 'r', 0 }, "gui_preferences" }, + { { 'r', 0 }, "record" }, +//{ { 'r', 0 }, "gui_preferences" }, { { 'c', 0 }, "gui_skinbrowser" }, { { 0 }, NULL } --- mplayer/input/input.h.recorder~ 2010-04-06 13:40:22.789040523 +0200 +++ mplayer/input/input.h 2010-04-06 13:40:22.795706994 +0200 @@ -133,6 +133,7 @@ typedef enum { MP_CMD_ASS_USE_MARGINS, MP_CMD_SWITCH_TITLE, MP_CMD_STOP, + MP_CMD_RECORD, /// DVDNAV commands MP_CMD_DVDNAV_UP = 1000, --- mplayer/Makefile.recorder~ 2010-04-06 13:40:22.789040523 +0200 +++ mplayer/Makefile 2010-04-06 13:40:22.795706994 +0200 @@ -531,6 +531,7 @@ SRCS_COMMON = asxparser.c \ stream/stream_mf.c \ stream/stream_null.c \ stream/url.c \ + stream/recorder.c \ $(SRCS_COMMON-yes) --- mplayer/mplayer.c.recorder~ 2010-04-06 13:40:22.789040523 +0200 +++ mplayer/mplayer.c 2010-04-06 13:40:22.799040334 +0200 @@ -124,6 +124,9 @@ char *heartbeat_cmd; #endif #include "stream/cache2.h" +extern void recorder_register_options(m_config_t* cfg); +extern void recorder_close(void); + //**************************************************************************// // Playtree //**************************************************************************// @@ -679,6 +682,9 @@ void uninit_player(unsigned int mask){ #endif } + current_module="uninit_recorder"; + recorder_close(); + current_module=NULL; } @@ -2647,6 +2653,7 @@ int gui_no_filename=0; mconfig = m_config_new(); m_config_register_options(mconfig,mplayer_opts); mp_input_register_options(mconfig); + recorder_register_options(mconfig); //HACK // Preparse the command line m_config_preparse_command_line(mconfig,argc,argv); @@ -2977,6 +2984,8 @@ stream_set_interrupt_callback(mp_input_c } #endif +setvbuf(stdin, 0, _IONBF, 0); + initialized_flags|=INITIALIZED_INPUT; current_module = NULL; --- mplayer/mp_msg.h.recorder~ 2010-04-06 13:16:58.000000000 +0200 +++ mplayer/mp_msg.h 2010-04-06 13:40:22.799040334 +0200 @@ -124,6 +124,8 @@ extern int verbose; #define MSGT_TELETEXT 46 // Teletext decoder +#define MSGT_RECORDER 63 + #define MSGT_MAX 64 void mp_msg_init(void); --- mplayer/stream/cache2.c.recorder~ 2010-04-06 13:16:52.000000000 +0200 +++ mplayer/stream/cache2.c 2010-04-06 13:43:46.752147495 +0200 @@ -58,6 +58,8 @@ static void *ThreadProc(void *s); #include "cache2.h" extern int use_gui; +void recorder_write(unsigned char *buffer, int len); + typedef struct { // constats: unsigned char *buffer; // base pointer of the alllocated buffer memory @@ -334,6 +336,7 @@ static void exit_sighandler(int x){ */ int stream_enable_cache(stream_t *stream,int size,int min,int seek_limit){ int ss = stream->sector_size ? stream->sector_size : STREAM_BUFFER_SIZE; + pid_t pid; int res = -1; cache_vars_t* s; @@ -344,6 +347,7 @@ int stream_enable_cache(stream_t *stream s=cache_init(size,ss); if(s == NULL) return -1; + stream->cache_pid=-1; stream->cache_data=s; s->stream=stream; // callback s->seek_limit=seek_limit; @@ -359,7 +363,9 @@ int stream_enable_cache(stream_t *stream } #if !defined(__MINGW32__) && !defined(PTHREAD_CACHE) && !defined(__OS2__) - if((stream->cache_pid=fork())){ + pid=fork(); + if(pid){ + stream->cache_pid = pid; if ((pid_t)stream->cache_pid == -1) stream->cache_pid = 0; #else @@ -439,7 +445,14 @@ static void ThreadProc( void *s ){ int cache_stream_fill_buffer(stream_t *s){ int len; if(s->eof){ s->buf_pos=s->buf_len=0; return 0; } - if(!s->cache_pid) return stream_fill_buffer(s); + if(s->cache_pid <= 0) { + len = stream_fill_buffer(s); + if(len <= 0) + return 0; + if(s->cache_pid == 0) + recorder_write(s->buffer, len); + return len; + } // cache_stats(s->cache_data); @@ -453,6 +466,7 @@ int cache_stream_fill_buffer(stream_t *s s->buf_len=len; s->pos+=len; // printf("[%d]",len);fflush(stdout); + recorder_write(s->buffer, len); return len; } @@ -460,7 +474,7 @@ int cache_stream_fill_buffer(stream_t *s int cache_stream_seek_long(stream_t *stream,off_t pos){ cache_vars_t* s; off_t newpos; - if(!stream->cache_pid) return stream_seek_long(stream,pos); + if(stream->cache_pid <= 0) return stream_seek_long(stream,pos); s=stream->cache_data; // s->seek_lock=1; --- mplayer/stream/recorder.c.recorder~ 2010-04-06 13:40:22.799040334 +0200 +++ mplayer/stream/recorder.c 2010-04-06 13:40:22.799040334 +0200 @@ -0,0 +1,181 @@ + +/* + * A simple (silly) stream recorder by Albeu + * Kept up to date and improved by bero <bero@arklinux.org> + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "../m_config.h" +#include "../m_option.h" +#include "mp_msg.h" + +static int record = 0; +static char append[2] = { 'w', 0 }; +static void* header = NULL; +static char* out_file = NULL; +static char* pipecmd = NULL; +static unsigned char* waitfor = NULL; +static unsigned int waitcount = 0; +static FILE* fd = NULL; + +static m_option_t recorder_opts[] = { + { "started", &record, CONF_TYPE_FLAG, 0, 0, 1, NULL }, + { "stopped", &record, CONF_TYPE_FLAG, 0, 1, 0, NULL }, + { NULL,NULL, 0, 0, 0, 0, NULL} +}; + +static m_option_t recorder_conf[] = { + { "recorder", &recorder_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, + { NULL,NULL, 0, 0, 0, 0, NULL} +}; + +void recorder_register_options(m_config_t* cfg) { + m_config_register_options(cfg,recorder_conf); +} + +void recorder_write(unsigned char* buffer,int len) { + int w; + + if(!record) + return; + + if (!fd) + { + if(pipecmd) + fd = popen(pipecmd, "w"); + else if(out_file) { + fd = fopen(out_file,append); + free(out_file); + out_file=NULL; + } else + fd = fopen("/home/andi/tmp/mplayer_record.stream", append); + if(!fd) { + mp_msg(MSGT_RECORDER,MSGL_ERR,"Unable to open recorder output file %s (%s)\n",out_file,strerror(errno)); + return; + } else { + mp_msg(MSGT_RECORDER,MSGL_V,"Recorder ready, recording in %s\n",out_file); + if(header) { + char buf[65536]; + FILE *hdr=fopen(header, "r"); + while(!feof(hdr) && !ferror(hdr)) { + int count=fread(buf, 1, 65536, hdr); + fwrite(buf, 1, count, fd); + } + fclose(hdr); + free(header); + header=NULL; + } + } + } + + if(waitcount) { + int i; + for(i=0; i<len-waitcount; i++) { + if(buffer[i]==waitfor[0]) { + int found=1, j; + for(j=1; j<waitcount; j++) { + if(buffer[i+j] != waitfor[j]) { + found=0; + break; + } + } + if(found) { + free(waitfor); + waitfor=NULL; + waitcount=0; + buffer += i; + len -= i; + break; + } + } + } + if(waitcount) + return; + } + + w = fwrite(buffer,len,1,fd); + if(w < 1) { + mp_msg(MSGT_RECORDER,MSGL_ERR,"Recorder : write error => disabeling the recorder\n"); + if(pipecmd) { + free(pipecmd); + pipecmd = NULL; + pclose(fd); + } else { + fclose(fd); + } + fd = NULL; + } +} + +void recorder_close(void) { + if(!fd) + return; + if(waitfor) { + free(waitfor); + waitfor=0; + } + if(pipecmd) { + if(pclose(fd) != 0) + mp_msg(MSGT_RECORDER,MSGL_ERR,"Recorder : close error (%s)\n",strerror(errno)); + free(pipecmd); + pipecmd = NULL; + } else { + if(fclose(fd) != 0) + mp_msg(MSGT_RECORDER,MSGL_ERR,"Recorder : close error (%s)\n",strerror(errno)); + } + fd = NULL; +} + +/* + * Flags: + * 1 ----> Append to existing file + * 2 ----> Prepend existing file + * 4 ----> Pipe to command + * 8 ----> Wait for specific data before recording + */ +void recorder_switch(char *name, int flags) { + if(name) { + if((flags & 2) && strchr(name, '%')) { + header=strdup(name); + *strchr(header, '%')=0; + strcpy(name, strchr(name, '%')+1); + } + if((flags & 8) && strchr(name, ':')) { + char *tmp=strdup(name); + int i; + *strchr(tmp, ':')=0; + strcpy(name, strchr(name, ':')+1); + waitfor=(char*) malloc(strlen(tmp)/2); + waitcount=0; + for(i=0; i<strlen(tmp); i+=2) { + char bytes[3]; + bytes[0]=tmp[i]; + bytes[1]=tmp[i+1]; + bytes[2]=0; + waitfor[waitcount++]=strtoul(bytes, NULL, 16); + } + free(tmp); + } + if(flags & 4) + pipecmd=strdup(name); + else + out_file=strdup(name); + } + if(!pipecmd && (flags & 1)) + append[0]='a'; + else + append[0]='w'; + record = record ? 0 : 1; + if(record) { + mp_msg(MSGT_RECORDER,MSGL_INFO,"\nStart recording\n"); + } else { + mp_msg(MSGT_RECORDER,MSGL_INFO,"\nStop recording\n"); + recorder_close(); + } +} --- mplayer/stream/stream.h.recorder~ 2010-04-06 13:16:52.000000000 +0200 +++ mplayer/stream/stream.h 2010-04-06 13:40:22.799040334 +0200 @@ -153,7 +153,7 @@ typedef struct stream_st { off_t pos,start_pos,end_pos; int eof; int mode; //STREAM_READ or STREAM_WRITE - unsigned int cache_pid; + pid_t cache_pid; void* cache_data; void* priv; // used for DVD, TV, RTSP etc char* url; // strdup() of filename/url