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