📄 ctrl.c
字号:
/* Ogle - A video player * Copyright (C) 2000, 2001 Bj鰎n Englund, H錵an Hjort * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/wait.h>#include <fcntl.h>#include <unistd.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/msg.h>#include <limits.h>#include <string.h>#include <errno.h>#include <signal.h>#include <ogle/msgevents.h>#include "mpeg.h"#include "common.h"#include "queue.h"#include "timemath.h"#include "debug_print.h"#ifndef SHM_SHARE_MMU#define SHM_SHARE_MMU 0#endif/* SA_SIGINFO isn't implemented yet on for example NetBSD */#if !defined(SA_SIGINFO)#define siginfo_t void#endifint create_msgq(void);int init_decoder(char *msgqid_str, char *decoderstr);int get_buffer(int size, shm_bufinfo_t *bufinfo);int create_q(int nr_of_elems, int buf_shmid, MsgEventClient_t writer, MsgEventClient_t reader);int create_ctrl_data(void);int register_stream(uint8_t stream_id, uint8_t subtype);static void handle_events(MsgEventQ_t *q, MsgEvent_t *ev);void int_handler(int sig);void sigchld_handler(int sig, siginfo_t *info, void* context);void remove_q_shm(void);void add_q_shmid(int shmid);void remove_q_shmid(int shmid);void destroy_msgq(void);void add_to_pidlist(pid_t pid, char *name);int remove_from_pidlist(pid_t pid);void cleanup_and_exit(void);void slay_children(void);int msgqid;int ctrl_data_shmid;ctrl_data_t *ctrl_data;char *program_name;int dlevel;char msgqid_str[9];char *input_file;char *framerate = NULL;char *output_bufs = NULL;char *file_offset = NULL;char *videodecode_debug = NULL;char *demux_debug = NULL;int ac3_audio_stream = -1;int dts_audio_stream = -1;int mpeg_audio_stream = -1;int lpcm_audio_stream = -1;int mpeg_video_stream = -1;int subpicture_stream = -1;int nav_stream = -1;char *ui = NULL;static int child_killed = 0;void usage(void){ fprintf(stderr, "Usage: %s [-h] [-u cli|gui] [<path>]\n", program_name); //"[-a <ac3_stream#>] [-m <mpeg_audio_stream#>] [-p <pcm_audio_stream#>] [-v <mpeg_video_stream#>] [-s <subpicture_stream#>] [-n] [-f <fps>] [-r <#ouput_bufs>] [-o <file_offset>] [-d <videodebug_level>] [-D <demuxdebug_level>] <input file>\n", program_name);}int next_client_id = CLIENT_UNINITIALIZED+1;int demux_registered = 0;MsgEventClient_t demux_client;typedef enum { CAP_started = 1, CAP_running = 2} cap_state_t;/* * a client can offer several different capabilities. * a client can offer several instances of the same capability. * several instances of the same client can exist. * an instance of a client can be identified by its MsgEventClient_t * a client ca be in two states, Started: it has been exec'd but * haven't registered itself. * Running: the client has registered itself and is ready. */typedef struct _capability_t { struct _capability_t *next; int capability; int nr_of_instances; int instances_in_use;} capability_t;typedef struct { MsgEventClient_t client; // client id int capabilities; // mask of all capabilities the client has capability_t *used_capabilities; // list of the capabilities in use cap_state_t state; // started, running pid_t pid; // pid of client char *exec_name; // file name of executable} process_info_t;typedef struct { MsgEventClient_t client; int caps; cap_state_t state; char *executable_file;} caps_t;static caps_t *caps_array = NULL;static int nr_caps = 0;int register_capabilities(MsgEventClient_t client, int caps, cap_state_t state){ if(nr_caps >= 20) { WARNING("%s", "more than 20 capabilities registered\n"); } nr_caps++; caps_array = realloc(caps_array, sizeof(caps_t)*nr_caps); caps_array[nr_caps-1].client = client; caps_array[nr_caps-1].caps = caps; caps_array[nr_caps-1].state = state; return 0;}int search_capabilities(int caps, MsgEventClient_t *client, int *ret_caps, cap_state_t *ret_state){ int n; int nr = 0; if(client != NULL) { *client = CLIENT_NONE; }#if DEBUG DNOTE("searching cap: %d\n", caps);#endif for(n = 0; n < nr_caps; n++) { if((caps_array[n].caps & caps) == caps) { nr++; if(client != NULL) { *client = caps_array[n].client;#if DEBUG DNOTE("found capclient: %ld\n", *client);#endif } if(ret_caps != NULL) { *ret_caps = caps_array[n].caps;#if DEBUG DNOTE("found cap: %x\n", *ret_caps);#endif }#if DEBUG DNOTE("state cap: %d\n", caps_array[n].state);#endif if(ret_state != NULL) { *ret_state = caps_array[n].state; } } } return nr;}static int streamid_to_capability(uint8_t stream_id, uint8_t subtype){ int cap = 0; if(stream_id == MPEG2_PRIVATE_STREAM_1) { if((subtype >= 0x80) && (subtype < 0x88)) { cap = DECODE_AC3_AUDIO; } else if((subtype >= 0x88) && (subtype < 0x90)) { cap = DECODE_DTS_AUDIO; } else if((subtype >= 0xA0) && (subtype < 0xA8)) { cap = DECODE_LPCM_AUDIO; } else if((subtype >= 0x20) && (subtype < 0x40)) { cap = DECODE_DVD_SPU; } } else if((stream_id >= 0xc0) && (stream_id < 0xe0)) { cap = DECODE_MPEG1_AUDIO | DECODE_MPEG2_AUDIO; } else if((stream_id >= 0xe0) && (stream_id < 0xf0)) { cap = DECODE_MPEG1_VIDEO | DECODE_MPEG2_VIDEO; } else if(stream_id == MPEG2_PRIVATE_STREAM_2) { cap = DECODE_DVD_NAV; } return cap;}static char *streamid_to_decoderstr(uint8_t stream_id, uint8_t subtype){ char *name = NULL; if(stream_id == MPEG2_PRIVATE_STREAM_1) { if((subtype >= 0x80) && (subtype < 0x88)) { name = getenv("DVDP_AC3"); } else if((subtype >= 0x88) && (subtype < 0x90)) { name = getenv("DVDP_DTS"); } else if((subtype >= 0xA0) && (subtype < 0xA8)) { name = getenv("DVDP_LPCM"); } else if((subtype >= 0x20) && (subtype < 0x40)) { name = getenv("DVDP_SPU"); } } else if((stream_id >= 0xc0) && (stream_id < 0xe0)) { name = getenv("DVDP_MPEGAUDIO"); } else if((stream_id >= 0xe0) && (stream_id < 0xf0)) { name = getenv("DVDP_VIDEO"); } else if(stream_id == MPEG2_PRIVATE_STREAM_2) { name = getenv("DVDP_VMG"); } return name;}static char *capability_to_decoderstr(int capability, int *ret_capability){ char *name = NULL; if((capability & DECODE_AC3_AUDIO) == capability) { name = getenv("DVDP_AC3"); *ret_capability = DECODE_AC3_AUDIO; } else if((capability & DECODE_DTS_AUDIO) == capability) { name = getenv("DVDP_DTS"); *ret_capability = DECODE_DTS_AUDIO; } else if((capability & (DECODE_MPEG1_AUDIO | DECODE_MPEG2_AUDIO)) == capability) { name = getenv("DVDP_MPEGAUDIO"); *ret_capability = DECODE_MPEG1_AUDIO | DECODE_MPEG2_AUDIO; } else if((capability & DECODE_DVD_SPU) == capability) { name = getenv("DVDP_SPU"); *ret_capability = (DECODE_DVD_SPU | VIDEO_OUTPUT); } else if((capability & (DECODE_MPEG1_VIDEO | DECODE_MPEG2_VIDEO)) == capability) { name = getenv("DVDP_VIDEO"); *ret_capability = DECODE_MPEG1_VIDEO | DECODE_MPEG2_VIDEO; } else if((capability & (DEMUX_MPEG1 | DEMUX_MPEG2_PS)) == capability) { name = getenv("DVDP_DEMUX"); *ret_capability = DEMUX_MPEG1 | DEMUX_MPEG2_PS; } else if((capability & (UI_DVD_CLI)) == capability) { name = getenv("DVDP_CLI_UI"); *ret_capability = UI_DVD_CLI; } else if((capability & (DECODE_DVD_NAV)) == capability) { name = getenv("DVDP_VMG"); *ret_capability = DECODE_DVD_NAV; } else if((capability & (UI_DVD_GUI)) == capability) { name = getenv("DVDP_UI"); *ret_capability = UI_DVD_GUI; } else if((capability & VIDEO_OUTPUT) == capability) { name = getenv("DVDP_VIDEO_OUT"); *ret_capability = (DECODE_DVD_SPU | VIDEO_OUTPUT); } return name;}static void cleanup(void){ //DNOTE("waiting for children to really die\n"); while(sleep(2)); // Continue sleeping if interupted slay_children(); cleanup_and_exit();}int request_capability(MsgEventQ_t *q, int cap, MsgEventClient_t *capclient, int *retcaps){ MsgEvent_t r_ev; char *decodername; cap_state_t state = 0;#if DEBUG DNOTE("_MsgEventQReqCapability\n");#endif if(!search_capabilities(cap, capclient, retcaps, &state)) { int fullcap; decodername = capability_to_decoderstr(cap, &fullcap); if(decodername != NULL) { register_capabilities(0, fullcap, CAP_started); //DNOTE("starting decoder %d %s\n", fullcap, decodername); init_decoder(msgqid_str, decodername); } } while(search_capabilities(cap, capclient, retcaps, &state) && (state != CAP_running)) { if(child_killed) { cleanup(); } if(MsgNextEventInterruptible(q, &r_ev) == -1) { switch(errno) { case EINTR: continue; break; } } handle_events(q, &r_ev); } if(state == CAP_running) {#if DEBUG DNOTE("sending ctrldata\n");#endif r_ev.type = MsgEventQCtrlData; r_ev.ctrldata.shmid = ctrl_data_shmid; MsgSendEvent(q, *capclient, &r_ev, 0); return 1; } else { ERROR("%s", "didn't find capability\n"); return 0; }}static void handle_events(MsgEventQ_t *q, MsgEvent_t *ev){ MsgEvent_t s_ev; MsgEvent_t r_ev; MsgEventClient_t rcpt; char *decodername; int capability; switch(ev->type) { case MsgEventQInitReq:#if DEBUG DNOTE("_MsgEventQInitReq, new_id: %d\n", next_client_id);#endif ev->type = MsgEventQInitGnt; ev->initgnt.newclientid = next_client_id++; MsgSendEvent(q, CLIENT_UNINITIALIZED, ev, 0); break; case MsgEventQRegister:#if DEBUG DNOTE("_MsgEventQRegister\n");#endif register_capabilities(ev->registercaps.client, ev->registercaps.capabilities, CAP_running); break; case MsgEventQReqCapability: { MsgEvent_t retev; retev.type = MsgEventQGntCapability; if(request_capability(q, ev->reqcapability.capability, &retev.gntcapability.capclient, &retev.gntcapability.capability)) { MsgSendEvent(q, ev->reqcapability.client, &retev, 0); } else { retev.gntcapability.client = CLIENT_NONE; MsgSendEvent(q, ev->reqcapability.client, &retev, 0); } } break; case MsgEventQReqBuf: { shm_bufinfo_t bufinfo; #if DEBUG DNOTE("_got request for buffer size %d\n", ev->reqbuf.size);#endif if(get_buffer(ev->reqbuf.size, &bufinfo) == -1) { bufinfo.shmid = -1; } s_ev.type = MsgEventQGntBuf; s_ev.gntbuf.shmid = bufinfo.shmid; s_ev.gntbuf.size = bufinfo.size; MsgSendEvent(q, ev->reqbuf.client, &s_ev, 0); } break; case MsgEventQDestroyBuf: { //DNOTE("_got destroy buffer shmid %d\n", ev->destroybuf.shmid); remove_q_shmid(ev->destroybuf.shmid); } break; case MsgEventQDestroyQ: { //DNOTE("_got destroy Q shmid %d\n", ev->detachq.q_shmid); remove_q_shmid(ev->detachq.q_shmid); } break; case MsgEventQReqStreamBuf: { int shmid; cap_state_t state = 0; DNOTE("_new stream %x, %x\n", ev->reqstreambuf.stream_id, ev->reqstreambuf.subtype); if(register_stream(ev->reqstreambuf.stream_id, ev->reqstreambuf.subtype)) { // this stream is wanted // check if we have a decoder //TODO check which decoder handles the stream and start it //if there isn't already one running that is free to use // TODO clean up logic/functions capability = streamid_to_capability(ev->reqstreambuf.stream_id, ev->reqstreambuf.subtype); // check if there is a decoder running or started if(!search_capabilities(capability, &rcpt, NULL, NULL)) { decodername = streamid_to_decoderstr(ev->reqstreambuf.stream_id, ev->reqstreambuf.subtype); if((capability & VIDEO_OUTPUT) || (capability & DECODE_DVD_SPU)) { DNOTE("%s", "registered VO or SPU started\n"); } if(capability == DECODE_DVD_SPU) { register_capabilities(0, DECODE_DVD_SPU | VIDEO_OUTPUT, CAP_started); } else { register_capabilities(0, capability, CAP_started); } // DNOTE("starting decoder %d %s\n", capability, decodername); init_decoder(msgqid_str, decodername); // DNOTE("started decoder %d\n", capability); } while(!search_capabilities(capability, &rcpt, NULL, &state) || (state != CAP_running)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -