1 /* 2 * Copyright 2019, Dario Casalinuovo. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "DVDMediaIO.h" 8 9 #include <stdio.h> 10 #include <unistd.h> 11 #include <inttypes.h> 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 16 #include "MediaDebug.h" 17 18 19 #define DVD_READ_CACHE 1 20 21 #define DEFAULT_LANGUAGE "en" 22 23 24 DVDMediaIO::DVDMediaIO(const char* path) 25 : 26 BAdapterIO( 27 B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, 28 B_INFINITE_TIMEOUT), 29 fPath(path), 30 fLoopThread(-1), 31 fExit(false) 32 { 33 fBuffer = (uint8_t*) malloc(DVD_VIDEO_LB_LEN); 34 } 35 36 37 DVDMediaIO::~DVDMediaIO() 38 { 39 fExit = true; 40 41 status_t status; 42 if (fLoopThread != -1) 43 wait_for_thread(fLoopThread, &status); 44 45 free(fBuffer); 46 } 47 48 49 ssize_t 50 DVDMediaIO::WriteAt(off_t position, const void* buffer, size_t size) 51 { 52 return B_NOT_SUPPORTED; 53 } 54 55 56 status_t 57 DVDMediaIO::SetSize(off_t size) 58 { 59 return B_NOT_SUPPORTED; 60 } 61 62 63 status_t 64 DVDMediaIO::Open() 65 { 66 fInputAdapter = BuildInputAdapter(); 67 68 if (dvdnav_open(&fDvdNav, fPath) != DVDNAV_STATUS_OK) { 69 TRACE("DVDMediaIO::Open() dvdnav_open error\n"); 70 return B_ERROR; 71 } 72 73 // read ahead cache usage 74 if (dvdnav_set_readahead_flag(fDvdNav, DVD_READ_CACHE) != DVDNAV_STATUS_OK) { 75 TRACE("DVDMediaIO::Open() dvdnav_set_readahead_flag error: %s\n", 76 dvdnav_err_to_string(fDvdNav)); 77 return B_ERROR; 78 } 79 80 // set language 81 if (dvdnav_menu_language_select(fDvdNav, DEFAULT_LANGUAGE) != DVDNAV_STATUS_OK || 82 dvdnav_audio_language_select(fDvdNav, DEFAULT_LANGUAGE) != DVDNAV_STATUS_OK || 83 dvdnav_spu_language_select(fDvdNav, DEFAULT_LANGUAGE) != DVDNAV_STATUS_OK) { 84 TRACE("DVDMediaIO::Open() setting languages error: %s\n", 85 dvdnav_err_to_string(fDvdNav)); 86 return B_ERROR; 87 } 88 89 // set the PGC positioning flag 90 if (dvdnav_set_PGC_positioning_flag(fDvdNav, 1) != DVDNAV_STATUS_OK) { 91 TRACE("DVDMediaIO::Open() dvdnav_set_PGC_positioning_flag error: %s\n", 92 dvdnav_err_to_string(fDvdNav)); 93 return 2; 94 } 95 96 fLoopThread = spawn_thread(_LoopThread, "two and two are five", 97 B_NORMAL_PRIORITY, this); 98 99 if (fLoopThread <= 0 || resume_thread(fLoopThread) != B_OK) 100 return B_ERROR; 101 102 return B_OK; 103 } 104 105 106 int32 107 DVDMediaIO::_LoopThread(void* data) 108 { 109 static_cast<DVDMediaIO *>(data)->LoopThread(); 110 return 0; 111 } 112 113 114 void 115 DVDMediaIO::LoopThread() 116 { 117 while (!fExit) { 118 int err; 119 int event; 120 int len; 121 122 #if DVD_READ_CACHE 123 err = dvdnav_get_next_cache_block(fDvdNav, &fBuffer, &event, &len); 124 #else 125 err = dvdnav_get_next_block(fDvdNav, fBuffer, &event, &len); 126 #endif 127 128 if (err == DVDNAV_STATUS_ERR) { 129 TRACE("DVDMediaIO::LoopThread(): Error getting next block: %s\n", 130 dvdnav_err_to_string(fDvdNav)); 131 continue; 132 } 133 134 HandleDVDEvent(event, len); 135 136 #if DVD_READ_CACHE 137 dvdnav_free_cache_block(fDvdNav, fBuffer); 138 #endif 139 } 140 141 if (dvdnav_close(fDvdNav) != DVDNAV_STATUS_OK) { 142 TRACE("DVDMediaIO::LoopThread() dvdnav_close error: %s\n", 143 dvdnav_err_to_string(fDvdNav)); 144 } 145 fLoopThread = -1; 146 } 147 148 149 void 150 DVDMediaIO::HandleDVDEvent(int event, int len) 151 { 152 switch (event) { 153 case DVDNAV_BLOCK_OK: 154 fInputAdapter->Write(fBuffer, len); 155 break; 156 157 case DVDNAV_NOP: 158 break; 159 160 case DVDNAV_STILL_FRAME: 161 { 162 dvdnav_still_event_t* still_event 163 = (dvdnav_still_event_t*) fBuffer; 164 if (still_event->length < 0xff) { 165 TRACE("DVDMediaIO::HandleDVDEvent: Skipped %d " 166 "seconds of still frame\n", 167 still_event->length); 168 } else { 169 TRACE("DVDMediaIO::HandleDVDEvent: Skipped " 170 "indefinite length still frame\n"); 171 } 172 dvdnav_still_skip(fDvdNav); 173 break; 174 } 175 176 case DVDNAV_WAIT: 177 TRACE("DVDMediaIO::HandleDVDEvent: Skipping wait condition\n"); 178 dvdnav_wait_skip(fDvdNav); 179 break; 180 181 case DVDNAV_SPU_CLUT_CHANGE: 182 break; 183 184 case DVDNAV_SPU_STREAM_CHANGE: 185 break; 186 187 case DVDNAV_AUDIO_STREAM_CHANGE: 188 break; 189 190 case DVDNAV_HIGHLIGHT: 191 { 192 dvdnav_highlight_event_t* highlight_event 193 = (dvdnav_highlight_event_t*) fBuffer; 194 TRACE("DVDMediaIO::HandleDVDEvent: Button: %d\n", 195 highlight_event->buttonN); 196 break; 197 } 198 199 case DVDNAV_VTS_CHANGE: 200 break; 201 202 case DVDNAV_CELL_CHANGE: 203 { 204 int32_t title = 0, chapter = 0; 205 uint32_t pos, len; 206 207 dvdnav_current_title_info(fDvdNav, &title, &chapter); 208 dvdnav_get_position(fDvdNav, &pos, &len); 209 TRACE("DVDMediaIO::HandleDVDEvent: Cell: Title %d, Chapter %d\n", 210 tt, ptt); 211 TRACE("DVDMediaIO::HandleDVDEvent: At position %.0f%% inside " 212 "the feature\n", 100 * (double)pos / (double)len); 213 break; 214 } 215 216 case DVDNAV_NAV_PACKET: 217 break; 218 219 case DVDNAV_HOP_CHANNEL: 220 break; 221 222 case DVDNAV_STOP: 223 fExit = true; 224 break; 225 226 default: 227 TRACE("DVDMediaIO::HandleDVDEvent: unknown event (%i)\n", 228 event); 229 fExit = true; 230 break; 231 } 232 } 233 234 235 status_t 236 DVDMediaIO::SeekRequested(off_t position) 237 { 238 dvdnav_sector_search(fDvdNav, position, SEEK_SET); 239 return B_OK; 240 } 241 242 243 void 244 DVDMediaIO::MouseMoved(uint32 x, uint32 y) 245 { 246 pci_t* pci = dvdnav_get_current_nav_pci(fDvdNav); 247 dvdnav_mouse_select(fDvdNav, pci, x, y); 248 } 249 250 251 void 252 DVDMediaIO::MouseDown(uint32 x, uint32 y) 253 { 254 pci_t* pci = dvdnav_get_current_nav_pci(fDvdNav); 255 dvdnav_mouse_activate(fDvdNav, pci, x, y); 256 } 257