static int dvdnav_stream_read(dvdnav_priv_t * priv, unsigned char *buf, int *len) { int event = DVDNAV_NOP; if (!len) return -1; *len=-1; if (!priv) return -1; if (!buf) return -1; if (dvd_nav_still) { mp_msg(MSGT_OPEN,MSGL_V, "%s: got a stream_read while I should be asleep!\n",__FUNCTION__); *len=0; return -1; } if (dvdnav_get_next_block(priv->dvdnav,buf,&event,len)!=DVDNAV_STATUS_OK) { mp_msg(MSGT_OPEN,MSGL_V, "Error getting next block from DVD %d (%s)\n",event, dvdnav_err_to_string(priv->dvdnav) ); *len=-1; } else if (event!=DVDNAV_BLOCK_OK) { // need to handle certain events internally (like skipping stills) switch (event) { case DVDNAV_NAV_PACKET: return event; case DVDNAV_STILL_FRAME: { dvdnav_still_event_t *still_event = (dvdnav_still_event_t*)(buf); //if (priv->started) dvd_nav_still=1; //else dvdnav_still_skip(priv->dvdnav); // don't let dvdnav stall on this image break; } case DVDNAV_HIGHLIGHT: { dvdnav_get_highlight (priv, 1); break; } case DVDNAV_CELL_CHANGE: { dvdnav_cell_change_event_t *ev = (dvdnav_cell_change_event_t*)buf; if(ev->pgc_length) priv->duration = ev->pgc_length/90; break; } case DVDNAV_SPU_CLUT_CHANGE: { memcpy(priv->spu_clut, buf, 16*sizeof(unsigned int)); priv->spu_set = 1; break; } case DVDNAV_WAIT: dvdnav_wait_skip(priv->dvdnav); break; } *len=0; } return event; }
static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { struct stream_priv_s* p = (struct stream_priv_s*)opts; char *filename; dvdnav_priv_t *priv; if(p->device) filename = p->device; else if(dvd_device) filename= dvd_device; else filename = DEFAULT_DVD_DEVICE; if(!(priv=new_dvdnav_stream(filename))) { mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,filename, strerror(errno)); return STREAM_UNSUPPORTED; } if(p->track > 0) { if(dvd_chapter > 0 && dvd_last_chapter > 0 && dvd_chapter > dvd_last_chapter) { mp_msg(MSGT_OPEN,MSGL_FATAL,"dvdnav_stream, invalid chapter range: %d > %d\n", dvd_chapter, dvd_last_chapter); return STREAM_UNSUPPORTED; } priv->title = p->track; if(dvdnav_title_play(priv->dvdnav, p->track) != DVDNAV_STATUS_OK) { mp_msg(MSGT_OPEN,MSGL_FATAL,"dvdnav_stream, couldn't select title %d, error '%s'\n", p->track, dvdnav_err_to_string(priv->dvdnav)); return STREAM_UNSUPPORTED; } if(dvd_chapter > 0) dvdnav_part_play(priv->dvdnav, p->track, dvd_chapter); } else if(p->track == -1) dvdnav_menu_call(priv->dvdnav, DVD_MENU_Root); else { mp_msg(MSGT_OPEN,MSGL_INFO,"dvdnav_stream, you didn't specify a track number (as in dvdnav://1), playing whole disc\n"); dvdnav_menu_call(priv->dvdnav, DVD_MENU_Title); } if(mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) identify(priv, p); if(dvd_angle > 1) dvdnav_angle_change(priv->dvdnav, dvd_angle); stream->sector_size = 2048; stream->flags = STREAM_READ | STREAM_SEEK; stream->fill_buffer = fill_buffer; stream->seek = seek; stream->control = control; stream->close = stream_dvdnav_close; stream->type = STREAMTYPE_DVDNAV; stream->priv=(void*)priv; *file_format = DEMUXER_TYPE_MPEG_PS; update_title_len(stream); if(!stream->pos) mp_msg(MSGT_OPEN,MSGL_ERR, "INIT ERROR: couldn't get init pos %s\r\n", dvdnav_err_to_string(priv->dvdnav)); mp_msg(MSGT_OPEN,MSGL_INFO, "Remember to disable MPlayer's cache when playing dvdnav:// streams (adding -nocache to your command line)\r\n"); return STREAM_OK; }
static int seek(stream_t *s, off_t newpos) { uint32_t sector = 0; dvdnav_priv_t *priv = s->priv; if(s->end_pos && newpos > s->end_pos) newpos = s->end_pos; sector = newpos / 2048ULL; if(dvdnav_sector_search(priv->dvdnav, (uint64_t) sector, SEEK_SET) != DVDNAV_STATUS_OK) goto fail; s->pos = newpos; return 1; fail: mp_msg(MSGT_STREAM,MSGL_INFO,"dvdnav_stream, seeking to %"PRIu64" failed: %s\n", newpos, dvdnav_err_to_string(priv->dvdnav)); return 1; }
static int dvdnav_stream_read(dvdnav_priv_t * priv, unsigned char *buf, int *len) { int event = DVDNAV_NOP; *len=-1; if (dvdnav_get_next_block(priv->dvdnav,buf,&event,len)!=DVDNAV_STATUS_OK) { mp_msg(MSGT_OPEN,MSGL_V, "Error getting next block from DVD %d (%s)\n",event, dvdnav_err_to_string(priv->dvdnav) ); *len=-1; } else if (event!=DVDNAV_BLOCK_OK) { // need to handle certain events internally (like skipping stills) switch (event) { case DVDNAV_NAV_PACKET: return event; case DVDNAV_STILL_FRAME: { dvdnav_still_event_t *still_event = (dvdnav_still_event_t *) buf; priv->still_length = still_event->length; /* set still frame duration */ priv->duration = dvdnav_get_duration (priv->still_length); if (priv->still_length <= 1) { pci_t *pnavpci = dvdnav_get_current_nav_pci (priv->dvdnav); priv->duration = mp_dvdtimetomsec (&pnavpci->pci_gi.e_eltm); } break; } case DVDNAV_HIGHLIGHT: { dvdnav_get_highlight (priv, 1); break; } case DVDNAV_CELL_CHANGE: { dvdnav_cell_change_event_t *ev = (dvdnav_cell_change_event_t*)buf; uint32_t nextstill; priv->state &= ~NAV_FLAG_WAIT_SKIP; priv->state |= NAV_FLAG_STREAM_CHANGE; if(ev->pgc_length) priv->duration = ev->pgc_length/90; if (dvdnav_is_domain_vts(priv->dvdnav)) { mp_msg(MSGT_IDENTIFY, MSGL_INFO, "DVDNAV_TITLE_IS_MOVIE\n"); priv->state &= ~NAV_FLAG_VTS_DOMAIN; } else { mp_msg(MSGT_IDENTIFY, MSGL_INFO, "DVDNAV_TITLE_IS_MENU\n"); priv->state |= NAV_FLAG_VTS_DOMAIN; } nextstill = dvdnav_get_next_still_flag (priv->dvdnav); if (nextstill) { priv->duration = dvdnav_get_duration (nextstill); priv->still_length = nextstill; if (priv->still_length <= 1) { pci_t *pnavpci = dvdnav_get_current_nav_pci (priv->dvdnav); priv->duration = mp_dvdtimetomsec (&pnavpci->pci_gi.e_eltm); } } break; } case DVDNAV_SPU_CLUT_CHANGE: { memcpy(priv->spu_clut, buf, 16*sizeof(unsigned int)); priv->state |= NAV_FLAG_SPU_SET; break; } case DVDNAV_WAIT: { if ((priv->state & NAV_FLAG_WAIT_SKIP) && !(priv->state & NAV_FLAG_WAIT)) dvdnav_wait_skip (priv->dvdnav); else priv->state |= NAV_FLAG_WAIT; break; } case DVDNAV_VTS_CHANGE: { priv->state &= ~NAV_FLAG_WAIT_SKIP; priv->state |= NAV_FLAG_STREAM_CHANGE; break; } case DVDNAV_SPU_STREAM_CHANGE: { priv->state |= NAV_FLAG_STREAM_CHANGE; break; } } *len=0; } return event; }
int main(int argc, char **argv) { dvdnav_t *dvdnav; uint8_t mem[DVD_VIDEO_LB_LEN]; int finished = 0; int output_fd = 0; int dump = 0, tt_dump = 0; /* open dvdnav handle */ printf("Opening DVD...\n"); if (dvdnav_open(&dvdnav, "/dev/dvd") != DVDNAV_STATUS_OK) { printf("Error on dvdnav_open\n"); return 1; } /* set read ahead cache usage */ if (dvdnav_set_readahead_flag(dvdnav, DVD_READ_CACHE) != DVDNAV_STATUS_OK) { printf("Error on dvdnav_set_readahead_flag: %s\n", dvdnav_err_to_string(dvdnav)); return 2; } /* set the language */ if (dvdnav_menu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK || dvdnav_audio_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK || dvdnav_spu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK) { printf("Error on setting languages: %s\n", dvdnav_err_to_string(dvdnav)); return 2; } /* set the PGC positioning flag to have position information relatively to the * whole feature instead of just relatively to the current chapter */ if (dvdnav_set_PGC_positioning_flag(dvdnav, 1) != DVDNAV_STATUS_OK) { printf("Error on dvdnav_set_PGC_positioning_flag: %s\n", dvdnav_err_to_string(dvdnav)); return 2; } /* the read loop which regularly calls dvdnav_get_next_block * and handles the returned events */ printf("Reading...\n"); while (!finished) { int result, event, len; uint8_t *buf = mem; /* the main reading function */ #if DVD_READ_CACHE result = dvdnav_get_next_cache_block(dvdnav, &buf, &event, &len); #else result = dvdnav_get_next_block(dvdnav, buf, &event, &len); #endif if (result == DVDNAV_STATUS_ERR) { printf("Error getting next block: %s\n", dvdnav_err_to_string(dvdnav)); return 3; } switch (event) { case DVDNAV_BLOCK_OK: /* We have received a regular block of the currently playing MPEG stream. * A real player application would now pass this block through demuxing * and decoding. We simply write it to disc here. */ if (!output_fd) { printf("Opening output...\n"); output_fd = open("libdvdnav.mpg", O_CREAT | O_WRONLY, S_IRWXU | S_IRWXG); if (output_fd == -1) { printf("Error opening output\n"); return 4; } } if (dump || tt_dump) write(output_fd, buf, len); break; case DVDNAV_NOP: /* Nothing to do here. */ break; case DVDNAV_STILL_FRAME: /* We have reached a still frame. A real player application would wait * the amount of time specified by the still's length while still handling * user input to make menus and other interactive stills work. * A length of 0xff means an indefinite still which has to be skipped * indirectly by some user interaction. */ { dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)buf; if (still_event->length < 0xff) printf("Skipping %d seconds of still frame\n", still_event->length); else printf("Skipping indefinite length still frame\n"); dvdnav_still_skip(dvdnav); } break; case DVDNAV_WAIT: /* We have reached a point in DVD playback, where timing is critical. * Player application with internal fifos can introduce state * inconsistencies, because libdvdnav is always the fifo's length * ahead in the stream compared to what the application sees. * Such applications should wait until their fifos are empty * when they receive this type of event. */ printf("Skipping wait condition\n"); dvdnav_wait_skip(dvdnav); break; case DVDNAV_SPU_CLUT_CHANGE: /* Player applications should pass the new colour lookup table to their * SPU decoder */ break; case DVDNAV_SPU_STREAM_CHANGE: /* Player applications should inform their SPU decoder to switch channels */ break; case DVDNAV_AUDIO_STREAM_CHANGE: /* Player applications should inform their audio decoder to switch channels */ break; case DVDNAV_HIGHLIGHT: /* Player applications should inform their overlay engine to highlight the * given button */ { dvdnav_highlight_event_t *highlight_event = (dvdnav_highlight_event_t *)buf; printf("Selected button %d\n", highlight_event->buttonN); } break; case DVDNAV_VTS_CHANGE: /* Some status information like video aspect and video scale permissions do * not change inside a VTS. Therefore this event can be used to query such * information only when necessary and update the decoding/displaying * accordingly. */ break; case DVDNAV_CELL_CHANGE: /* Some status information like the current Title and Part numbers do not * change inside a cell. Therefore this event can be used to query such * information only when necessary and update the decoding/displaying * accordingly. */ { int tt = 0, ptt = 0, pos, len; char input = '\0'; dvdnav_current_title_info(dvdnav, &tt, &ptt); dvdnav_get_position(dvdnav, &pos, &len); printf("Cell change: Title %d, Chapter %d\n", tt, ptt); printf("At position %.0f%% inside the feature\n", 100 * (double)pos / (double)len); dump = 0; if (tt_dump && tt != tt_dump) tt_dump = 0; if (!dump && !tt_dump) { fflush(stdin); while ((input != 'a') && (input != 's') && (input != 'q') && (input != 't')) { printf("(a)ppend cell to output\n(s)kip cell\nappend until end of (t)itle\n(q)uit\n"); scanf("%c", &input); } switch (input) { case 'a': dump = 1; break; case 't': tt_dump = tt; break; case 'q': finished = 1; } } } break; case DVDNAV_NAV_PACKET: /* A NAV packet provides PTS discontinuity information, angle linking information and * button definitions for DVD menus. Angles are handled completely inside libdvdnav. * For the menus to work, the NAV packet information has to be passed to the overlay * engine of the player so that it knows the dimensions of the button areas. */ { pci_t *pci; dsi_t *dsi; /* Applications with fifos should not use these functions to retrieve NAV packets, * they should implement their own NAV handling, because the packet you get from these * functions will already be ahead in the stream which can cause state inconsistencies. * Applications with fifos should therefore pass the NAV packet through the fifo * and decoding pipeline just like any other data. */ pci = dvdnav_get_current_nav_pci(dvdnav); dsi = dvdnav_get_current_nav_dsi(dvdnav); if(pci->hli.hl_gi.btn_ns > 0) { int button; printf("Found %i DVD menu buttons...\n", pci->hli.hl_gi.btn_ns); for (button = 0; button < pci->hli.hl_gi.btn_ns; button++) { btni_t *btni = &(pci->hli.btnit[button]); printf("Button %i top-left @ (%i,%i), bottom-right @ (%i,%i)\n", button + 1, btni->x_start, btni->y_start, btni->x_end, btni->y_end); } button = 0; while ((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) { printf("Which button (1 to %i): ", pci->hli.hl_gi.btn_ns); scanf("%i", &button); } printf("Selecting button %i...\n", button); /* This is the point where applications with fifos have to hand in a NAV packet * which has traveled through the fifos. See the notes above. */ dvdnav_button_select_and_activate(dvdnav, pci, button); } } break; case DVDNAV_HOP_CHANNEL: /* This event is issued whenever a non-seamless operation has been executed. * Applications with fifos should drop the fifos content to speed up responsiveness. */ break; case DVDNAV_STOP: /* Playback should end here. */ { finished = 1; } break; default: printf("Unknown event (%i)\n", event); finished = 1; break; } #if DVD_READ_CACHE dvdnav_free_cache_block(dvdnav, buf); #endif } /* destroy dvdnav handle */ if (dvdnav_close(dvdnav) != DVDNAV_STATUS_OK) { printf("Error on dvdnav_close: %s\n", dvdnav_err_to_string(dvdnav)); return 5; } close(output_fd); return 0; }
void k9PlayMPEG2::playTitle() { dvdnav_t *dvdnav; uint8_t mem[DVD_VIDEO_LB_LEN]; int finished = 0; int32_t tt = 0,ptt=0; uint32_t pos, lgr; int title=m_title->getnumTitle(); /* open dvdnav handle */ if (dvdnav_open(&dvdnav, m_device,m_dvd) != DVDNAV_STATUS_OK) { setError("ERR:Error on dvdnav_open\n"); return ; } /* set read ahead cache usage */ if (dvdnav_set_readahead_flag(dvdnav, DVD_READ_CACHE) != DVDNAV_STATUS_OK) { setError(QString("ERR:Error on dvdnav_set_readahead_flag: %1\n").arg(dvdnav_err_to_string(dvdnav))); return; } /* set the language */ if (dvdnav_menu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK || dvdnav_audio_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK || dvdnav_spu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK) { setError(QString("ERR:Error on setting languages: %1\n").arg(dvdnav_err_to_string(dvdnav))); return ; } /* set the PGC positioning flag to have position information relatively to the * whole feature instead of just relatively to the current chapter */ if (dvdnav_set_PGC_positioning_flag(dvdnav, 1) != DVDNAV_STATUS_OK) { setError(QString("ERR:Error on dvdnav_set_PGC_positioning_flag: %1\n").arg(dvdnav_err_to_string(dvdnav))); return ; } int32_t parts; dvdnav_get_number_of_parts(dvdnav , title, &parts); if (m_chapter==0) dvdnav_title_play(dvdnav , title); else dvdnav_part_play(dvdnav , title,m_chapter); /* the read loop which regularly calls dvdnav_get_next_block * and handles the returned events */ while (!finished && !m_stopped && qApp!=NULL) { int result, event, len; uint8_t *buf = mem; if (m_idxLect !=0xFFFFFFFF) { dvdnav_sector_search(dvdnav, m_idxLect,SEEK_SET); m_idxLect=0xFFFFFFFF; } /* the main reading function */ #ifdef DVD_READ_CACHE result = dvdnav_get_next_cache_block(dvdnav, &buf, &event, &len); #else result = dvdnav_get_next_block(dvdnav, buf, &event, &len); #endif if (result == DVDNAV_STATUS_ERR) { setError(QString("ERR:Error getting next block: %1\n").arg(dvdnav_err_to_string(dvdnav))); return; } switch (event) { case DVDNAV_NAV_PACKET: { dvdnav_current_title_info(dvdnav, &tt, &ptt); dvdnav_get_position(dvdnav, &pos, &lgr); if (tt != title) finished=1; if (finished==0 && buf[17]==0xE0) { m_decoder.addData( buf,len); } if (qApp->tryLock()) { emit setPosition( pos); qApp->unlock(); } } break; //removed break --> save case DVDNAV_BLOCK_OK: /* We have received a regular block of the currently playing MPEG stream.*/ m_decoder.addData( buf,len); break; case DVDNAV_NOP: /* Nothing to do here. */ break; case DVDNAV_STILL_FRAME: /* We have reached a still frame. A real player application would wait * the amount of time specified by the still's length while still handling * user input to make menus and other interactive stills work. * A length of 0xff means an indefinite still which has to be skipped * indirectly by some user interaction. */ { dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)buf; dvdnav_still_skip(dvdnav); } break; case DVDNAV_WAIT: /* We have reached a point in DVD playback, where timing is critical. * Player application with internal fifos can introduce state * inconsistencies, because libdvdnav is always the fifo's length * ahead in the stream compared to what the application sees. * Such applications should wait until their fifos are empty * when they receive this type of event. */ dvdnav_wait_skip(dvdnav); break; case DVDNAV_SPU_CLUT_CHANGE: /* Player applications should pass the new colour lookup table to their * SPU decoder */ break; case DVDNAV_SPU_STREAM_CHANGE: /* Player applications should inform their SPU decoder to switch channels */ break; case DVDNAV_AUDIO_STREAM_CHANGE: /* Player applications should inform their audio decoder to switch channels */ break; case DVDNAV_HIGHLIGHT: /* Player applications should inform their overlay engine to highlight the * given button */ { dvdnav_highlight_event_t *highlight_event = (dvdnav_highlight_event_t *)buf; } break; case DVDNAV_VTS_CHANGE: /* Some status information like video aspect and video scale permissions do * not change inside a VTS. Therefore this event can be used to query such * information only when necessary and update the decoding/displaying * accordingly. */ break; case DVDNAV_CELL_CHANGE: // dvdnav_get_position(dvdnav, &pos, &lgr); break; case DVDNAV_HOP_CHANNEL: /* This event is issued whenever a non-seamless operation has been executed. * Applications with fifos should drop the fifos content to speed up responsiveness. */ break; case DVDNAV_STOP: /* Playback should end here. */ { finished = 1; } break; default: finished = 1; break; } #ifdef DVD_READ_CACHE dvdnav_free_cache_block(dvdnav, buf); #endif } m_decoder.setNoData(); /* destroy dvdnav handle */ dvdnav_close(dvdnav); }