📄 nav.c
字号:
/* Ogle - A video player * Copyright (C) 2000, 2001 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 <stdio.h>#include <stdlib.h>#include <unistd.h>#include <inttypes.h>#include <string.h>#include <assert.h>#include <time.h>#include <ogle/msgevents.h>#include <ogle/dvdevents.h>#include "debug_print.h"#include <dvdread/nav_types.h>#include <dvdread/nav_read.h>#include <dvdread/nav_print.h>#include "vm.h"#include "interpret_config.h"extern int wait_q(MsgEventQ_t *msgq, MsgEvent_t *ev); // com.cextern int get_q(MsgEventQ_t *msgq, unsigned char *buffer);extern void wait_for_init(MsgEventQ_t *msgq);extern void handle_events(MsgEventQ_t *msgq, MsgEvent_t *ev);extern int send_demux(MsgEventQ_t *msgq, MsgEvent_t *ev);extern int send_spu(MsgEventQ_t *msgq, MsgEvent_t *ev);extern char *get_dvdroot(void);extern void free_dvdroot(void);extern dvd_state_t state;extern unsigned char discid[16];MsgEvent_t dvdroot_return_ev;MsgEventClient_t dvdroot_return_client;static void do_run(void);static int process_user_data(MsgEvent_t ev, pci_t *pci, dsi_t *dsi, cell_playback_t *cell, int block, int *still_time);static void time_convert(DVDTimecode_t *dest, dvd_time_t *source){ dest->Hours = bcd2int(source->hour); dest->Minutes = bcd2int(source->minute); dest->Seconds = bcd2int(source->second); dest->Frames = bcd2int(source->frame_u & 0x3f);}MsgEventQ_t *msgq;char *program_name;int dlevel;void usage(void){ fprintf(stderr, "Usage: %s -m <msgqid>\n", program_name);}int main(int argc, char *argv[]){ int msgqid = -1; int c; program_name = argv[0]; GET_DLEVEL(); /* Parse command line options */ while ((c = getopt(argc, argv, "m:h?")) != EOF) { switch (c) { case 'm': msgqid = atoi(optarg); break; case 'h': case '?': usage(); exit(1); } } if(msgqid == -1) { fprintf(stderr, "what?\n"); exit(1); } srand(getpid()); { MsgEvent_t ev; if((msgq = MsgOpen(msgqid)) == NULL) { FATAL("%s", "couldn't get message q\n"); exit(1); } ev.type = MsgEventQRegister; ev.registercaps.capabilities = DECODE_DVD_NAV; if(MsgSendEvent(msgq, CLIENT_RESOURCE_MANAGER, &ev, 0) == -1) { FATAL("%s", "registering capabilities\n"); exit(1); } ev.type = MsgEventQReqCapability; ev.reqcapability.capability = DEMUX_MPEG2_PS | DEMUX_MPEG1; if(MsgSendEvent(msgq, CLIENT_RESOURCE_MANAGER, &ev, 0) == -1) { FATAL("%s", "didn't get demux cap\n"); exit(1); } ev.type = MsgEventQReqCapability; ev.reqcapability.capability = DECODE_DVD_SPU; if(MsgSendEvent(msgq, CLIENT_RESOURCE_MANAGER, &ev, 0) == -1) { FATAL("%s", "didn't get spu cap\n"); exit(1); } vm_reset(); interpret_config(); while(1) { wait_for_init(msgq); /* Call start here */ // hack placed here because it calls DVDOpen... DNOTE("Opening DVD at \"%s\"\n", get_dvdroot()); if(vm_init(get_dvdroot()) == -1) { // Failure, don't quit... just let the app know we didn't succeed dvdroot_return_ev.dvdctrl.cmd.retval.val = DVD_E_RootNotSet; MsgSendEvent(msgq, dvdroot_return_client, &dvdroot_return_ev, 0); free_dvdroot(); } else { // Success, send ok and breakout of loop dvdroot_return_ev.dvdctrl.cmd.retval.val = DVD_E_Ok; MsgSendEvent(msgq, dvdroot_return_client, &dvdroot_return_ev, 0); break; } } ev.type = MsgEventQDemuxDVDRoot; strncpy(ev.demuxdvdroot.path, get_dvdroot(), sizeof(ev.demuxdvdroot.path)); ev.demuxdvdroot.path[sizeof(ev.demuxdvdroot.path)-1] = '\0'; if(send_demux(msgq, &ev) == -1) { FATAL("%s", "failed sending dvdroot to demuxer\n"); exit(1); } ev.type = MsgEventQDemuxStream; ev.demuxstream.stream_id = 0xe0; // Mpeg1/2 Video ev.demuxstream.subtype = 0; if(send_demux(msgq, &ev) == -1) { FATAL("%s", "failed setting demux video stream id\n"); exit(1); } ev.type = MsgEventQDemuxStream; ev.demuxstream.stream_id = 0xbd; // AC3 1 ev.demuxstream.subtype = 0x80; if(send_demux(msgq, &ev) == -1) { FATAL("%s", "failed setting demux AC3 stream id\n"); exit(1); } ev.type = MsgEventQDemuxStream; ev.demuxstream.stream_id = 0xbd; // SPU 1 ev.demuxstream.subtype = 0x20; if(send_demux(msgq, &ev) == -1) { FATAL("%s", "failed setting demux subpicture stream id\n"); exit(1); } ev.type = MsgEventQDemuxStream; ev.demuxstream.stream_id = 0xbf; // NAV ev.demuxstream.subtype = 0; if(send_demux(msgq, &ev) == -1) { FATAL("%s", "failed setting demux NAV stream id\n"); exit(1); } } //vm_reset(get_dvdroot()); do_run(); return 0;}/** * Update any info the demuxer needs, and then tell the demuxer * what range of sectors to process. */static void send_demux_sectors(int start_sector, int nr_sectors, FlowCtrl_t flush) { static int video_aspect = -1; // static int audio_stream_id = -1; static int subp_stream_id = -1; MsgEvent_t ev; /* Tell video out what aspect ratio this pice has */ { video_attr_t attr = vm_get_video_attr(); if(attr.display_aspect_ratio != video_aspect) { video_aspect = attr.display_aspect_ratio; //DNOTE("sending aspect %s\n", video_aspect ? "16:9" : "4:3"); ev.type = MsgEventQSetSrcAspect; ev.setsrcaspect.mode_src = AspectModeSrcVM; if(video_aspect) { ev.setsrcaspect.aspect_frac_n = 16; ev.setsrcaspect.aspect_frac_d = 9; } else { ev.setsrcaspect.aspect_frac_n = 4; ev.setsrcaspect.aspect_frac_d = 3; } /* !!! FIXME should be sent to video out not spu */ if(send_spu(msgq, &ev) == -1) { ERROR("%s", "failed to send aspect info\n"); } } } /* Tell the demuxer which audio stream to demux */ { int sN = vm_get_audio_stream(state.AST_REG); if(sN < 0 || sN > 7) sN = 7; // XXX == -1 for _no audio_ { static uint8_t old_id = 0xbd; static uint8_t old_subtype = 0x80; uint8_t new_id; uint8_t new_subtype; audio_attr_t attr; int audio_stream_id = sN; new_id = 0; new_subtype = 0; attr = vm_get_audio_attr(sN); switch(attr.audio_format) { case 0: //af = DVD_AUDIO_FORMAT_AC3; new_id = 0xbd; //private stream 1 new_subtype = 0x80 + audio_stream_id; // AC-3 break; case 2: //af = DVD_AUDIO_FORMAT_MPEG1; new_id = 0xC0 + audio_stream_id; //mpeg audio case 3: //af = DVD_AUDIO_FORMAT_MPEG2; new_id = 0xC0 + audio_stream_id; //mpeg audio break; case 4: //af = DVD_AUDIO_FORMAT_LPCM; new_id = 0xbd; //private stream 1 new_subtype = 0xA0 + audio_stream_id; // lpcm break; case 6: //af = DVD_AUDIO_FORMAT_DTS; new_id = 0xbd; //private stream 1 new_subtype = 0x88 + audio_stream_id; // dts break; default: NOTE("%s", "please send a bug report, unknown Audio format!"); break; } if(old_id != new_id || old_subtype != new_subtype) { DNOTE("sending audio demuxstream %d\n", sN); DNOTE("oid: %02x, ost: %02x, nid: %02x, nst: %02x\n", old_id, old_subtype, new_id, new_subtype); ev.type = MsgEventQDemuxStreamChange2; ev.demuxstreamchange2.old_stream_id = old_id; ev.demuxstreamchange2.old_subtype = old_subtype; ev.demuxstreamchange2.new_stream_id = new_id; ev.demuxstreamchange2.new_subtype = new_subtype; if(send_demux(msgq, &ev) == -1) { ERROR("%s", "failed to send audio demuxstream\n"); } } old_id = new_id; old_subtype = new_subtype; } } /* Tell the demuxer which subpicture stream to demux */ { int sN = vm_get_subp_active_stream(); if(sN < 0 || sN > 31) sN = 31; // XXX == -1 for _no audio_ if(sN != subp_stream_id) { subp_stream_id = sN; DNOTE("sending subp demuxstream %d\n", sN); ev.type = MsgEventQDemuxStreamChange; ev.demuxstreamchange.stream_id = 0xbd; // SPU ev.demuxstreamchange.subtype = 0x20 | subp_stream_id; if(send_demux(msgq, &ev) == -1) { ERROR("%s", "failed to send Subpicture demuxstream\n"); } } } /* Tell the demuxer what file and which sectors to demux. */ ev.type = MsgEventQDemuxDVD; if(state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) ev.demuxdvd.titlenum = 0; else ev.demuxdvd.titlenum = state.vtsN; if(state.domain == VTS_DOMAIN) ev.demuxdvd.domain = DVD_READ_TITLE_VOBS; else ev.demuxdvd.domain = DVD_READ_MENU_VOBS; ev.demuxdvd.block_offset = start_sector; ev.demuxdvd.block_count = nr_sectors; ev.demuxdvd.flowcmd = flush; if(send_demux(msgq, &ev) == -1) { FATAL("%s", "failed to send demux dvd block range\n"); exit(1); } //DNOTE("sent demux dvd block range (%d,%d)\n", start_sector, nr_sectors);}static void send_spu_palette(uint32_t palette[16]) { MsgEvent_t ev; int i; ev.type = MsgEventQSPUPalette; for(i = 0; i < 16; i++) { ev.spupalette.colors[i] = palette[i]; } //DNOTE("sending subpicture palette\n"); if(send_spu(msgq, &ev) == -1) { ERROR("%s", "failed sending subpicture palette\n"); }}static void send_highlight(int x_start, int y_start, int x_end, int y_end, uint32_t btn_coli) { MsgEvent_t ev; int i; ev.type = MsgEventQSPUHighlight; ev.spuhighlight.x_start = x_start; ev.spuhighlight.y_start = y_start; ev.spuhighlight.x_end = x_end; ev.spuhighlight.y_end = y_end; for(i = 0; i < 4; i++) ev.spuhighlight.color[i] = 0xf & (btn_coli >> (16 + 4*i)); for(i = 0; i < 4; i++) ev.spuhighlight.contrast[i] = 0xf & (btn_coli >> (4*i)); if(send_spu(msgq, &ev) == -1) { ERROR("%s", "faild sending highlight info\n"); }}/** * Check if mouse coords are over any highlighted area. * * @return The button number if the the coordinate is enclosed in the area. * Zero otherwise. */int mouse_over_hl(pci_t *pci, unsigned int x, unsigned int y) { int button = 1; while(button <= pci->hli.hl_gi.btn_ns) { if( (x >= pci->hli.btnit[button-1].x_start) && (x <= pci->hli.btnit[button-1].x_end) && (y >= pci->hli.btnit[button-1].y_start) && (y <= pci->hli.btnit[button-1].y_end )) return button; button++; } return 0;}/** * Update the highligted button in response to an input event. * Also send highlight information to the spu_mixer. * * @return One if the (possibly updated) button is activated. * Zero otherwise. */static int process_button(DVDCtrlEvent_t *ce, pci_t *pci, uint16_t *btn_reg) { /* Keep the button register value in a local variable. */ uint16_t button_nr = (*btn_reg) >> 10; int tmp, is_action = 0; /* MORE CODE HERE :) */ /* Paranoia.. */ // No highlight/button pci info to use or no buttons if((pci->hli.hl_gi.hli_ss & 0x03) == 0 || pci->hli.hl_gi.btn_ns == 0) return 0; // Selected button > than max button? then cap it if(button_nr > pci->hli.hl_gi.btn_ns) button_nr = pci->hli.hl_gi.btn_ns; // Selected button should never be 0. if(button_nr == 0) { //FATAL("%s", "send bug report, button number is 0, this is invalid."); button_nr = 1; *btn_reg = button_nr << 10; } switch(ce->type) { case DVDCtrlUpperButtonSelect: button_nr = pci->hli.btnit[button_nr - 1].up; break; case DVDCtrlLowerButtonSelect: button_nr = pci->hli.btnit[button_nr - 1].down; break; case DVDCtrlLeftButtonSelect: button_nr = pci->hli.btnit[button_nr - 1].left; break; case DVDCtrlRightButtonSelect: button_nr = pci->hli.btnit[button_nr - 1].right; break; case DVDCtrlButtonActivate: is_action = 1; break; case DVDCtrlButtonSelectAndActivate: is_action = 1; /* Fall through */ case DVDCtrlButtonSelect: tmp = ce->button.nr - pci->hli.hl_gi.btn_ofn; if(tmp > 0 && tmp <= pci->hli.hl_gi.nsl_btn_ns) button_nr = tmp; else /* not a valid button */ is_action = 0; break; case DVDCtrlMouseActivate: is_action = 1; /* Fall through */ case DVDCtrlMouseSelect:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -