00001
00002
00003 #include <stdio.h>
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include <signal.h>
00007 #include <fcntl.h>
00008 #include <unistd.h>
00009 #include <stdlib.h>
00010
00011 #include <iostream>
00012
00013 #include "mplayer.h"
00014 #include "iniparser.h"
00015
00016 using namespace std;
00017
00018 void MPlayerFactory::registerParameters(ParamSection *sec) {
00019 sec->addStringParam("mplayer.input", &input_string, "movie.avi");
00020 sec->addBoolParam("mplayer.use", &use, true);
00021 sec->addStringParam("mplayer.mencoder", &mencoder, "mencoder");
00022 sec->addStringParam("mplayer.options", &mencoder_options, "-ovc raw -of rawvideo -vf format=bgr24 -quiet");
00023 };
00024
00025 VideoSource *MPlayerFactory::construct() {
00026 if (use) {
00027 MPlayerVideoSource *vs = new MPlayerVideoSource(input_string, mencoder, mencoder_options);
00028 if (vs->initialize()) return vs;
00029 delete vs;
00030 }
00031 return 0;
00032 }
00033
00034 MPlayerVideoSource::MPlayerVideoSource(char *input_string, char *mencoder, char *options)
00035 : input_string(input_string), mencoder(mencoder), mencoder_options(options)
00036 {
00037 frameCnt=0;
00038 playing=true;
00039 pipe_dir[0]=0;
00040 video_pipe[0]=0;
00041 info_pipe=0;
00042 data_pipe=-1;
00043 tmp_im=0;
00044 }
00045
00046
00047 bool MPlayerVideoSource::initialize()
00048 {
00049
00050 sprintf(pipe_dir, "/tmp/vsmencXXXXXX");
00051
00052 if (mkdtemp(pipe_dir)==0) {
00053 perror(pipe_dir);
00054 return false;
00055 }
00056
00057 snprintf(video_pipe, sizeof(video_pipe), "%s/pipe", pipe_dir);
00058
00059 if (mknod(video_pipe, S_IFIFO | S_IREAD | S_IWRITE, 0) <0) {
00060 perror("Named pipe");
00061 rmdir(pipe_dir);
00062 pipe_dir[0]=0;
00063 return false;
00064 }
00065
00066 snprintf(mencoder_cmd, sizeof(mencoder_cmd), "%s %s %s -o %s",
00067 mencoder, mencoder_options, input_string, video_pipe);
00068
00069 return execPlayer();
00070 }
00071
00072 static bool searchString(FILE *f, const char *s) {
00073 int i=0;
00074
00075 while (1) {
00076 int c = fgetc(f);
00077
00078 if (feof(f)) return false;
00079
00080 fputc(c,stdout);
00081
00082 if (c==s[i]) {
00083 i++;
00084 if (s[i]==0) return true;
00085 } else
00086 i=0;
00087 }
00088 return false;
00089
00090 }
00091
00092 bool MPlayerVideoSource::execPlayer() {
00093
00094 assert(data_pipe<0);
00095 assert(info_pipe==0);
00096
00097 data_pipe = open(video_pipe,O_RDONLY | O_NONBLOCK);
00098
00099 if (data_pipe < 0) {
00100 perror(video_pipe);
00101 return false;
00102 }
00103
00104
00105 fcntl(data_pipe, F_SETFL, fcntl(data_pipe, F_GETFL) & (~O_NONBLOCK));
00106
00107 #ifdef BIDIR_PIPE
00108 if (pipe.open(mencoder_cmd,"r")==0) {
00109 perror(mencoder_cmd);
00110 return(false);
00111 }
00112 info_pipe = pipe.read;
00113 #else
00114 info_pipe = popen(mencoder_cmd, "r");
00115 if (info_pipe ==0) {
00116 perror(mencoder_cmd);
00117 return false;
00118 }
00119 #endif
00120
00121 if (!searchString(info_pipe, "success:")
00122 || !searchString(info_pipe, "VDec: vo config request - ")) {
00123 closePlayer();
00124 return false;
00125 }
00126
00127 if (fscanf(info_pipe, "%d %*c %d", &width, &height) <= 0) {
00128 fprintf(stderr, "Error while reading mencoder output: unable to determine image resolution.");
00129 closePlayer();
00130 return false;
00131 }
00132
00133
00134 fcntl(fileno(info_pipe), F_SETFL, fcntl(fileno(info_pipe), F_GETFL) |O_NONBLOCK);
00135
00136
00137 readInfo();
00138
00139 return true;
00140 }
00141
00142 void MPlayerVideoSource::closePlayer()
00143 {
00144 if (data_pipe >= 0) {
00145
00146 fcntl(data_pipe, F_SETFL, fcntl(data_pipe, F_GETFL) | O_NONBLOCK);
00147 close(data_pipe);
00148 }
00149 data_pipe=-1;
00150
00151 if (info_pipe) {
00152 readInfo();
00153
00154 #ifdef BIDIR_PIPE
00155 pipe.close(true);
00156 #else
00157 close(fileno(info_pipe));
00158 pclose(info_pipe);
00159 #endif
00160 }
00161 info_pipe=0;
00162 }
00163
00164 void MPlayerVideoSource::readInfo() {
00165 char str[80];
00166 int n=0;
00167
00168 while (!feof(info_pipe)) {
00169 n = fread(str, 1, sizeof(str), info_pipe);
00170 if (n>0) {
00171 fwrite(str, 1, n, stdout);
00172 } else
00173 return;
00174 }
00175 }
00176
00177 bool MPlayerVideoSource::getFrame(IplImage *dst)
00178 {
00179 if (playing) {
00180 int bytes = width*height*3;
00181
00182 IplImage *read_to;
00183 if ((width == dst->width) && (height == dst->height))
00184 read_to = dst;
00185 else {
00186 if (tmp_im ==0) tmp_im = cvCreateImage(cvSize(width,height), IPL_DEPTH_8U,3);
00187 read_to = tmp_im;
00188 }
00189
00190 int got=0;
00191 do {
00192 readInfo();
00193 int n = read(data_pipe, read_to->imageData+got, bytes-got);
00194 if (n<0) {
00195 printf("read() returned %d\n", n);
00196 playing = false;
00197 return false;
00198 }
00199 if (frameCnt>0 && n==0) {
00200
00201 closePlayer();
00202 if (!execPlayer()) return false;
00203 frameCnt=0;
00204 got=0;
00205 }
00206
00207 got += n;
00208 } while (got!= bytes);
00209
00210
00211 if (read_to == tmp_im)
00212 cvResize(tmp_im, dst);
00213
00214 frameCnt++;
00215 }
00216
00217 return true;
00218 }
00219
00220 int MPlayerVideoSource::getId()
00221 {
00222 if (playing) return frameCnt-1;
00223 return frameCnt;
00224 }
00225
00226 MPlayerVideoSource::~MPlayerVideoSource() {
00227 cout << "now closing mencoder.\n";
00228 closePlayer();
00229 if (video_pipe[0]) unlink(video_pipe);
00230 if (strlen(pipe_dir)>0) rmdir(pipe_dir);
00231 if (tmp_im) cvReleaseImage(&tmp_im);
00232 }
00233
00234 void MPlayerVideoSource::start() {
00235 playing = true;
00236 }
00237
00238 void MPlayerVideoSource::stop() {
00239 playing = false;
00240 }
00241
00242 void MPlayerVideoSource::getSize(int &width, int &height)
00243 {
00244 width = this->width;
00245 height = this->height;
00246 }