📄 video_output.c
字号:
sleeptime.tv_nsec = TIME_SS(time_left)*(1000000000/CT_FRACTION); nanosleep(&sleeptime, NULL); clocktime_get(&real_time); calc_realtime_left_to_scrtime(&time_left, &real_time, scr, sp); return time_left; } else { // less than clktck/2 left or negative time left, we cant sleep // a shorter period than clktck so we return return time_left; } while(!end_of_wait) { MsgEvent_t ev; // check any events that arrives if(MsgNextEventInterruptible(msgq, &ev) == -1) { switch(errno) { case EINTR: end_of_wait = 1; break; default: FATAL("%s", "waiting for notification"); perror("MsgNextEvent"); // might never have had dispay_init called display_exit(); //clean up and exit break; } } else { timer.it_value.tv_sec = 0; // disable timer timer.it_value.tv_usec = 0; // disable timer setitimer(ITIMER_REAL, &timer, NULL); event_handler(msgq, &ev); if(redraw_needed) { redraw_screen(); } break; } } timer.it_value.tv_sec = 0; // disable timer timer.it_value.tv_usec = 0; // disable timer setitimer(ITIMER_REAL, &timer, NULL); sigaction(SIGALRM, &oact, NULL); } }static int get_next_picture_q_elem_id(data_q_t *data_q){ int elem; MsgEvent_t ev; struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 0; elem = data_q->q_head->read_nr; //DNOTE("get_next_picture_q_elem_id: elem: %d\n", elem); data_q->q_head->read_nr = (data_q->q_head->read_nr+1)%data_q->q_head->nr_of_qelems; if(!data_q->q_elems[elem].in_use) { data_q->q_head->reader_requests_notification = 1; //DNOTE("elem not in use, setting notification req\n"); while(!data_q->q_elems[elem].in_use) { if(process_interrupted) { // might never have had dispay_init called display_exit(); } timer.it_value.tv_usec = 100000; //0.1 sec setitimer(ITIMER_REAL, &timer, NULL); //DNOTE("waiting for notification\n"); if(MsgNextEventInterruptible(msgq, &ev) == -1) { switch(errno) { case EINTR: continue; break; default: FATAL("%s", "waiting for notification"); perror("MsgNextEvent"); // might never have had dispay_init called? display_exit(); //clean up and exit break; } } timer.it_value.tv_usec = 0; // disable timer setitimer(ITIMER_REAL, &timer, NULL); event_handler(msgq, &ev); if(redraw_needed) { redraw_screen(); } } } if((data_q->q_elems[elem].data_elem_index) == -1) { // end of q data_q->eoq = 1; return -1; } data_q->in_use++; return elem;}static void release_picture(int q_elem_id, data_q_t *data_q){ MsgEvent_t ev; int msg_sent = 0; int id; id = data_q->q_elems[q_elem_id].data_elem_index; /* DNOTE("release_picture: elem: %d, buf: %d\n", q_elem_id, id); */ data_q->data_elems[id].displayed = 1; data_q->q_elems[q_elem_id].in_use = 0; if(data_q->q_head->writer_requests_notification) { data_q->q_head->writer_requests_notification = 0; ev.type = MsgEventQNotify; do { if(process_interrupted) { display_exit(); } if(MsgSendEvent(msgq, data_q->q_head->writer, &ev, IPC_NOWAIT) == -1) { MsgEvent_t c_ev; switch(errno) { case EAGAIN: WARNING("%s", "msgq full, checking incoming messages and trying again\n"); while(MsgCheckEvent(msgq, &c_ev) != -1) { event_handler(msgq, &c_ev); } break;#ifdef EIDRM case EIDRM:#endif case EINVAL: FATAL("%s", "couldn't send notification no msgq\n"); display_exit(); //TODO clean up and exit break; default: FATAL("%s", "couldn't send notification\n"); display_exit(); //TODO clean up and exit break; } } else { msg_sent = 1; } } while(!msg_sent); } data_q->in_use--;}data_q_t *get_next_data_q(data_q_t **head, data_q_t *cur_q){ data_q_t **data_q; data_q_t *tmp_q; for(data_q = head; *data_q != NULL && *data_q != cur_q; data_q = &(*data_q)->next); if(*data_q == NULL) { ERROR("%s", "get_next_data_q(), couldn't find cur_q\n"); return NULL; } tmp_q = (*data_q)->next; //pointer to the next q if(!(*data_q)->in_use) { display_reset(); detach_data_q((*data_q)->q_head->qid, head); } if(tmp_q == NULL) { // no next q, lets wait for it DNOTE("%s", "get_next_data_q: no next q\n"); wait_for_q_attach(); if(*data_q != cur_q) { //cur has been detached tmp_q = *data_q; } else { tmp_q = (*data_q)->next; } } return tmp_q;}/* Erhum test... */clocktime_t first_time;int frame_nr = 0;static void int_handler(int sig){ process_interrupted = 1;}static void display_process(){ clocktime_t real_time, prefered_time, frame_interval; clocktime_t avg_time, oavg_time;#ifndef HAVE_CLOCK_GETTIME clocktime_t waittmp;#endif clocktime_t wait_time; struct sigaction sig; int q_elem_id = -1; int prev_q_elem_id = -1; int buf_id = -1; int prev_buf_id = -1; int old_q_id = -1; int drop = 0; int avg_nr = 23; picture_data_elem_t *pinfos; data_q_t *old_data_q = NULL; TIME_S(prefered_time) = 0; sig.sa_handler = int_handler; sig.sa_flags = 0; sigaction(SIGINT, &sig, NULL); sig.sa_handler = alarm_handler; sig.sa_flags = 0; sigaction(SIGALRM, &sig, NULL); talk_to_xscreensaver = look_for_good_xscreensaver(); while(1) { //DNOTE("old_q_id: %d\n", old_q_id); old_data_q = cur_data_q; do { q_elem_id = get_next_picture_q_elem_id(cur_data_q); /* DNOTE("get_next_picture_q_elem_id: %d, buf:%d\n", q_elem_id, cur_data_q->q_elems[q_elem_id].data_elem_index); */ if(cur_data_q->eoq) { //end of q /* last pic in the current q, switch to new q, and detach the old if there is no new q, wait for an attachq or appendq get first pic in the new q */ if(!cur_data_q->in_use) { last_image_buf = NULL; old_data_q = NULL; } cur_data_q = get_next_data_q(&data_q_head, cur_data_q); } } while(q_elem_id == -1); pinfos = cur_data_q->data_elems; buf_id = cur_data_q->q_elems[q_elem_id].data_elem_index; //DNOTE("last_image_buf: %d\n", last_image_buf); video_scr_nr = pinfos[buf_id].scr_nr; // Consume all messages for us and spu_mixer if(msgqid != -1) { MsgEvent_t ev; while(MsgCheckEvent(msgq, &ev) != -1) { event_handler(msgq, &ev); } } if(ctrl_time[pinfos[buf_id].scr_nr].sync_master <= SYNC_VIDEO) { ctrl_time[pinfos[buf_id].scr_nr].sync_master = SYNC_VIDEO; //TODO release scr_nr when done if(ctrl_time[pinfos[buf_id].scr_nr].offset_valid == OFFSET_NOT_VALID) { if(pinfos[buf_id].PTS_DTS_flags & 0x2) { clocktime_t scr_time; DNOTE("%s", "set_sync_point()\n"); PTS_TO_CLOCKTIME(scr_time, pinfos[buf_id].PTS); clocktime_get(&real_time); set_sync_point(&ctrl_time[pinfos[buf_id].scr_nr], &real_time, &scr_time, ctrl_data->speed); } } /* if(pinfos[buf_id].PTS_DTS_flags & 0x2) { time_offset = get_time_base_offset(pinfos[buf_id].PTS, ctrl_time, pinfos[buf_id].scr_nr); } */ prev_scr_nr = pinfos[buf_id].scr_nr; } PTS_TO_CLOCKTIME(frame_interval, pinfos[buf_id].frame_interval); clocktime_get(&real_time); TIME_S(wait_time) = 0; TIME_SS(wait_time) = 0; if(flush_to_scrid != -1) { if(ctrl_time[video_scr_nr].scr_id >= flush_to_scrid) { flush_to_scrid = -1; } } if(flush_to_scrid == -1) { if(TIME_S(prefered_time) == 0 || TIME_SS(frame_interval) == 1) { prefered_time = real_time; } else if(ctrl_time[pinfos[buf_id].scr_nr].offset_valid == OFFSET_NOT_VALID) { prefered_time = real_time; } else /* if(TIME_S(pinfos[buf_id].pts_time) != -1) */ { clocktime_t pts_time; PTS_TO_CLOCKTIME(pts_time, pinfos[buf_id].PTS); /* calc_realtime_from_scrtime(&prefered_time, &pts_time, &ctrl_time[pinfos[buf_id].scr_nr].sync_point); */ wait_time = wait_until(&pts_time, &ctrl_time[pinfos[buf_id].scr_nr].sync_point); } } /** * We have waited and now it's time to show a new picture */ last_image_buf = &cur_data_q->image_bufs[buf_id]; // release the old picture, if it's not done already if(prev_buf_id != -1) { if(old_q_id != cur_data_q->q_head->qid) { //DNOTE("old_q_id != current\n"); } if((old_data_q != NULL) && (old_data_q != cur_data_q)) { //DNOTE("release old_q buf_id: %d\n", prev_buf_id); release_picture(prev_q_elem_id, old_data_q); } else { //DNOTE("release buf_id: %d\n", prev_buf_id); release_picture(prev_q_elem_id, cur_data_q); } } else if(prev_q_elem_id != -1) { //DNOTE("release2 buf_id: %d\n", prev_buf_id); release_picture(prev_q_elem_id, cur_data_q); } //detach old q if any if(old_q_id != cur_data_q->q_head->qid) { if(old_q_id != -1) { detach_data_q(old_q_id, &data_q_head); } /* DNOTE("display_init: width: %d, height:%d\n", cur_data_q->data_head->info.video.width, cur_data_q->data_head->info.video.height); */ display_init(cur_data_q->data_head->info.video.width, cur_data_q->data_head->info.video.height, cur_data_q->data_head->shmid, (char *)cur_data_q->data_head); } prev_q_elem_id = q_elem_id; prev_buf_id = buf_id; old_q_id = cur_data_q->q_head->qid; /* fprintf(stderr, "*vo: waittime: %ld.%+010ld\n", wait_time.tv_sec, wait_time.tv_nsec); */ if(TIME_SS(wait_time) < -60*(CT_FRACTION/1000)) { // more than 60 ms late, drop decoded pictures drop = 1; } if(!drop) { frame_nr++; avg_nr++; } if(avg_nr == 200) { avg_nr = 0; oavg_time = avg_time; clocktime_get(&avg_time); fprintf(stderr, "display: frame rate: %.3f fps\n", 200.0/(((double)TIME_S(avg_time)+ (double)TIME_SS(avg_time)/CT_FRACTION)- ((double)TIME_S(oavg_time)+ (double)TIME_SS(oavg_time)/CT_FRACTION)) ); } /* clocktime_get(&real_time2); timesub(&diff, &prefered_time, &real_time2); fprintf(stderr, "diff: %d.%+010ld\n", TIME_S(diff), TIME_SS(diff)); */ /* fprintf(stderr, "rt: %d.%09ld, pt: %d.%09ld, diff: %d.%+09ld\n", TIME_S(real_time2), TIME_SS(real_time2), TIME_S(prefered_time), TIME_SS(prefered_time), TIME_S(diff), TIME_SS(diff)); */ if(!drop) { if(flush_to_scrid != -1) { if(ctrl_time[video_scr_nr].scr_id < flush_to_scrid) { redraw_done(); } else { flush_to_scrid = -1; display(&cur_data_q->image_bufs[buf_id]); redraw_done(); } } else { display(&cur_data_q->image_bufs[buf_id]); redraw_done(); } } else { fprintf(stderr, "#"); drop = 0; } }}void display_process_exit(void) { exit(0);}#ifdef __bsdi__static int bsdi_getticks(void){ int mib[2]; size_t olen = sizeof (struct clockinfo); struct clockinfo ci; mib[0] = CTL_KERN; mib[1] = KERN_CLOCKRATE; if (sysctl(mib, 2, &ci, &olen, NULL, 0) < 0) { perror("sysctl kern.clockrate"); return(100); } return ci.hz;}#endifstatic void usage(){ fprintf(stderr, "Usage: %s [-m <msgid>]\n", program_name);}int main(int argc, char **argv){ MsgEvent_t ev; 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(); return 1; } } if(msgqid == -1) { if(argc - optind != 1){ usage(); return 1; } } errno = 0;#ifdef __bsdi__ clk_tck = bsdi_getticks();#else clk_tck = sysconf(_SC_CLK_TCK);#endif if(clk_tck <= 0) { // linux returns 0 as error also if(errno != 0 && clk_tck == -1) { perror("sysconf(_SC_CLK_TCK)"); } else { fprintf(stderr, "sysconf(_SC_CLK_TCK), not supported\n"); } //guessed default value clk_tck = 100; } min_time_left = (CT_FRACTION/clk_tck)/2; DNOTE("CLK_TCK: %ld\n", clk_tck); if(msgqid != -1) { if((msgq = MsgOpen(msgqid)) == NULL) { FATAL("%s", "couldn't get message q\n"); exit(1); } register_event_handler(handle_events); init_spu(); ev.type = MsgEventQRegister; ev.registercaps.capabilities = VIDEO_OUTPUT | DECODE_DVD_SPU; if(MsgSendEvent(msgq, CLIENT_RESOURCE_MANAGER, &ev, 0) == -1) { DPRINTF(1, "vo: register capabilities\n"); exit(1); //TODO clean up and exit } //DNOTE("sent caps\n"); ev.type = MsgEventQReqCapability; ev.reqcapability.capability = UI_DVD_GUI; if(MsgSendEvent(msgq, CLIENT_RESOURCE_MANAGER, &ev, 0) == -1) { FATAL("%s", "didn't get dvd_gui cap\n"); exit(1); //TODO clean up and exit } //DNOTE("waiting for attachq\n"); while(ev.type != MsgEventQAttachQ) { if(MsgNextEventInterruptible(msgq, &ev) == -1) { switch(errno) { case EINTR: continue; break; default: FATAL("%s", "waiting for attachq"); perror("MsgNextEvent"); exit(1); break; } } event_handler(msgq, &ev); } //DNOTE("got attachq\n"); display_process(); } else { fprintf(stderr, "what?\n"); } exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -