summaryrefslogtreecommitdiffstats
path: root/codecctrl.c
blob: 23b424308f56c6e802c3adeb5d08a941f9b24c0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//#define DEBUG_SIGNALS
#define DEBUG_SIGNALS_SLEEP ;
//#define DEBUG_SIGNALS_SLEEP sleep(2);

#ifdef DEBUG_SIGNALS
#define DEBUG_SIG if(1)
#else
#define DEBUG_SIG if(0)
#endif

//======= Interprocess Comminication (IPC) between player & codec =========

static int child_pid=0;
static int codec_pid=0;

// player:
static int data_fifo=-1;
static int control_fifo=-1;
// codec:
static int data_fifo2=-1;
static int control_fifo2=-1;
// keyboard:
static int keyb_fifo_put=-1;
static int keyb_fifo_get=-1;


// SIGTERM handler of codec controller (2nd process):
static void codec_ctrl_sighandler(int x){
DEBUG_SIG  printf("\nCTRL: received signal %d, terminating child first:\n",x);
  // first terminate the codec:
  //kill(child_pid,SIGTERM);
  kill(child_pid,x);
  usleep(50000); // 50ms must be enough
DEBUG_SIG  printf("CTRL: Sending KILL signal to child:\n");
  kill(child_pid,SIGKILL); // worst case
  usleep(10000);
  // and exit
  if(x!=SIGHUP){
DEBUG_SIG    printf("CTRL: Exiting...\n");
    exit(0);
  }
}

static vo_functions_t *codec_video_out_ptr=NULL;

// SIGTERM handler of the codec (3nd process):
static void codec_sighandler(int x){
DEBUG_SIG  printf("\nCHILD: received signal %d, exiting...\n",x);
  if(x==SIGTERM){
    //mpeg2_close(codec_video_out_ptr);
    codec_video_out_ptr->uninit();  // closing video_out
  }
  exit(0);
}


static void make_pipe(int* pr,int* pw){
  int temp[2];
  if(pipe(temp)!=0) printf("Cannot make PIPE!\n");
  *pr=temp[0];
  *pw=temp[1];
}

static inline int my_write(int fd,unsigned char* mem,int len){
  int total=0;
  int len2;
  while(len>0){
    len2=write(fd,mem+total,len); if(len2<=0) break;
    total+=len2;len-=len2;
//    printf("%d bytes received, %d left\n",len2,len);
  }
  return total;
}

static inline int my_read(int fd,unsigned char* mem,int len){
  int total=0;
  int len2;
  while(len>0){
    len2=read(fd,mem+total,len); if(len2<=0) break;
    total+=len2;len-=len2;
//    printf("%d bytes received, %d left\n",len2,len);
  }
  return total;
}


void send_cmd(int fd,int cmd){
  int fifo_cmd=cmd;
  write(fd,&fifo_cmd,4);
//  fflush(control_fifo);
}

void mpeg_codec_controller(vo_functions_t *video_out){
//================== CODEC Controller: ==========================
    signal(SIGTERM,codec_ctrl_sighandler); // set our SIGTERM handler
    signal(SIGHUP,codec_ctrl_sighandler);  // set our SIGHUP handler
    printf("starting video codec...\n");
    while(1){
      int status;
      if((child_pid=fork())==0){
        // child:
        unsigned int t=0;
        codec_video_out_ptr=video_out;
#if 0
        signal(SIGTERM,codec_sighandler); // set our SIGTERM handler
        signal(SIGHUP,codec_sighandler);  // set our SIGHUP handler
#else
  // terminate requests:
  signal(SIGTERM,codec_sighandler); // kill
  signal(SIGHUP,codec_sighandler);  // kill -HUP  /  xterm closed
  signal(SIGINT,codec_sighandler);  // Interrupt from keyboard
  signal(SIGQUIT,codec_sighandler); // Quit from keyboard
  // fatal errors:
  signal(SIGBUS,codec_sighandler);  // bus error
  signal(SIGSEGV,codec_sighandler); // segfault
  signal(SIGILL,codec_sighandler);  // illegal instruction
  signal(SIGFPE,codec_sighandler);  // floating point exc.
  signal(SIGABRT,codec_sighandler); // abort()
#endif

        send_cmd(control_fifo2,0x22222222); // Send WE_ARE_READY command
        send_cmd(control_fifo2,getpid());   // Send out PID
        while(1){
          unsigned int syncword=0;
          read(data_fifo2,&syncword,4);
          if(syncword==0x22222222) break;
          printf("codec: drop bad frame (%X)\n",syncword);
        }
        //printf("codec: connection synced\n");
        
        while(1){
          int num_frames;
          int len=0;
          int len2;
          send_cmd(control_fifo2,0x3030303);
          len2=my_read(data_fifo2,(unsigned char*) &len,4);
          if(len2!=4){
            printf("FATAL: cannot read packet len from data fifo (ret=%d, errno=%d)\n",len2,errno);
            break;
          }
          if(len==0){ printf("mpeg2dec: EOF, exiting...\n");break; }
//          printf("mpeg2dec: frame (%d bytes) read\n",len);
          t-=GetTimer();
          mpeg2_decode_data(video_out, videobuffer, videobuffer+len);
          t+=GetTimer();
          send_cmd(control_fifo2,0); // FRAME_COMPLETED command
          send_cmd(control_fifo2,picture->frame_rate); // fps
          send_cmd(control_fifo2,100+picture->repeat_count);picture->repeat_count=0;
          send_cmd(control_fifo2,t);t=0;
        }
		video_out->uninit();
        exit(0); // leave process
      }
      wait(&status); // Waiting for the child!
//      printf("restarting video codec...\n");
    }
    exit(0);
}

void mplayer_put_key(int code){
           fd_set rfds;
           struct timeval tv;

           /* Watch stdin (fd 0) to see when it has input. */
           FD_ZERO(&rfds);
           FD_SET(keyb_fifo_put, &rfds);
           tv.tv_sec = 0;
           tv.tv_usec = 0;

           //retval = select(keyb_fifo_put+1, &rfds, NULL, NULL, &tv);
           if(select(keyb_fifo_put+1, NULL, &rfds, NULL, &tv)){
             write(keyb_fifo_put,&code,4);
//             printf("*** key event %d sent ***\n",code);
           } else {
//             printf("*** key event dropped (FIFO is full) ***\n");
           }
}

int mplayer_get_key(){
           fd_set rfds;
           struct timeval tv;
           int code=-1;

           /* Watch stdin (fd 0) to see when it has input. */
           FD_ZERO(&rfds);
           FD_SET(keyb_fifo_get, &rfds);
           tv.tv_sec = 0;
           tv.tv_usec = 0;

           //retval = select(keyb_fifo_put+1, &rfds, NULL, NULL, &tv);
           if(select(keyb_fifo_put+1, &rfds, NULL, NULL, &tv)){
             read(keyb_fifo_get,&code,4);
//             printf("*** key event %d read ***\n",code);
           }
           return code;
}