]> git.vomp.tv Git - vompclient-marten.git/blob - videomvp.cc
libCEC support
[vompclient-marten.git] / videomvp.cc
1 /*\r
2     Copyright 2004-2005 Chris Tallon\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19 */\r
20 \r
21 #include "videomvp.h"\r
22 \r
23 // temp\r
24 #include "log.h"\r
25 \r
26 VideoMVP::VideoMVP()\r
27 {\r
28   if (instance) return;\r
29 }\r
30 \r
31 VideoMVP::~VideoMVP()\r
32 {\r
33   instance = NULL;\r
34 }\r
35 \r
36 int VideoMVP::init(UCHAR tformat)\r
37 {\r
38   if (initted) return 0;\r
39   initted = 1;\r
40 \r
41   if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;\r
42 \r
43   if (!setFormat(tformat))           { shutdown(); return 0; }\r
44   if (!setConnection(COMPOSITERGB))  { shutdown(); return 0; }\r
45   if (!setAspectRatio(ASPECT4X3))    { shutdown(); return 0; }\r
46   if (!setMode(NORMAL))              { shutdown(); return 0; }\r
47   if (!setSource())                  { shutdown(); return 0; }\r
48   if (!attachFrameBuffer())          { shutdown(); return 0; }\r
49 \r
50   setTVsize(ASPECT4X3);\r
51 \r
52   if (format == PAL) setLetterboxBorder("38");\r
53   else setLetterboxBorder("31");\r
54 \r
55   stop();\r
56 \r
57 \r
58   return 1;\r
59 }\r
60 \r
61 void VideoMVP::setLetterboxBorder(char* border)\r
62 {\r
63   FILE* fdlbox = fopen("/proc/lbox_border", "w");\r
64   if (!fdlbox) return;\r
65   fputs(border, fdlbox);\r
66   fclose(fdlbox);\r
67 }\r
68 \r
69 int VideoMVP::setTVsize(UCHAR ttvsize)\r
70 {\r
71   tvsize = ttvsize;\r
72 \r
73   // Override the aspect ratio usage, temporarily use to set the video chip mode\r
74   if (!setAspectRatio(tvsize))       { shutdown(); return 0; }\r
75   close(fdVideo);\r
76   if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;\r
77   if (!setSource())                  { shutdown(); return 0; }\r
78   if (!attachFrameBuffer())          { shutdown(); return 0; }\r
79 \r
80   // Reopening the fd causes the scart aspect line to go back to 4:3\r
81   // Set this again to the same as the tv screen size\r
82   if (!setAspectRatio(tvsize))       { shutdown(); return 0; }\r
83 \r
84   // mode == LETTERBOX is invalid if the TV is widescreen\r
85   if (tvsize == ASPECT16X9) setMode(NORMAL);\r
86 \r
87   return 1;\r
88 }\r
89 \r
90 int VideoMVP::setDefaultAspect()\r
91 {\r
92   return setAspectRatio(tvsize);\r
93 }\r
94 \r
95 int VideoMVP::shutdown()\r
96 {\r
97   if (!initted) return 0;\r
98   initted = 0;\r
99   close(fdVideo);\r
100   return 1;\r
101 }\r
102 \r
103 int VideoMVP::checkSCART()\r
104 {\r
105   // Returns 3 for SCART Composite out\r
106   // Returns 3 for SCART S-Video out\r
107   // Returns 2 for SCART RGB out\r
108   // Returns 3 for SCART not plugged in\r
109 \r
110   // So, as you can have RGB and composite out simultaneously,\r
111   // and it can't detect S-Video, what is the point of this?\r
112 \r
113   int scart;\r
114   if (ioctl(fdVideo, AV_CHK_SCART, &scart) != 0) return -10;\r
115 \r
116   return scart;\r
117 }\r
118 \r
119 int VideoMVP::setFormat(UCHAR tformat)\r
120 {\r
121   if (!initted) return 0;\r
122   if ((tformat != PAL) && (tformat != NTSC)) return 0;\r
123   format = tformat;\r
124 \r
125   if (ioctl(fdVideo, AV_SET_VID_DISP_FMT, format) != 0) return 0;\r
126 \r
127   if (format == NTSC)\r
128   {\r
129     screenWidth = 720;\r
130     screenHeight = 480;\r
131   }\r
132   if (format == PAL)\r
133   {\r
134     screenWidth = 720;\r
135     screenHeight = 576;\r
136   }\r
137 \r
138   return 1;\r
139 }\r
140 \r
141 int VideoMVP::setConnection(UCHAR tconnection)\r
142 {\r
143   if (!initted) return 0;\r
144   if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;\r
145   connection = tconnection;\r
146 \r
147   if (ioctl(fdVideo, AV_SET_VID_OUTPUT, connection) != 0) return 0;\r
148   return 1;\r
149 }\r
150 \r
151 int VideoMVP::setAspectRatio(UCHAR taspectRatio)\r
152 {\r
153   if (!initted) return 0;\r
154   if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;\r
155   aspectRatio = taspectRatio;\r
156 \r
157   Log::getInstance()->log("Video", Log::DEBUG, "Setting aspect to %i", aspectRatio);\r
158 \r
159   if (ioctl(fdVideo, AV_SET_VID_RATIO, aspectRatio) != 0) return 0;\r
160   return 1;\r
161 }\r
162 \r
163 int VideoMVP::setMode(UCHAR tmode)\r
164 {\r
165   if (!initted) return 0;\r
166 \r
167   if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode\r
168 \r
169   if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)\r
170       && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;\r
171   mode = tmode;\r
172 \r
173   if (ioctl(fdVideo, AV_SET_VID_MODE, mode) != 0) return 0;\r
174   return 1;\r
175 }\r
176 \r
177 int VideoMVP::signalOff()\r
178 {\r
179   if (ioctl(fdVideo, AV_SET_VID_DENC, 0) != 0) return 0;\r
180   return 1;\r
181 }\r
182 \r
183 int VideoMVP::signalOn()\r
184 {\r
185   if (ioctl(fdVideo, AV_SET_VID_DENC, 1) != 0) return 0;\r
186   return 1;\r
187 }\r
188 \r
189 int VideoMVP::setSource()\r
190 {\r
191   if (!initted) return 0;\r
192 \r
193   // What does this do...\r
194   if (ioctl(fdVideo, AV_SET_VID_SRC, 1) != 0) return 0;\r
195   return 1;\r
196 }\r
197 \r
198 int VideoMVP::setPosition(int x, int y)\r
199 {\r
200   if (!initted) return 0;\r
201 \r
202 //  vid_pos_regs_t pos_d;\r
203 //  pos_d.x = x;\r
204 //  pos_d.y = y;\r
205 \r
206   vid_pos_regs_t pos_d;\r
207 \r
208   memset(&pos_d, 0, sizeof(pos_d));\r
209 \r
210   pos_d.dest.y = y;\r
211   pos_d.dest.x = x;\r
212 /*\r
213 typedef struct {\r
214   int w;\r
215   int h;\r
216   int scale;\r
217   int x1;\r
218   int y;\r
219   int x;\r
220   int y2;\r
221   int x3;\r
222   int y3;\r
223   int x4;\r
224   int y4;\r
225 } vid_pos_regs_t;\r
226 */\r
227 \r
228 /*\r
229   pos_d.w = 100;\r
230   pos_d.h = 30;\r
231   pos_d.scale = 2;\r
232   pos_d.x1 = 0;\r
233   pos_d.y = 100;            // Top left X\r
234   pos_d.x = 50;            // Top left Y\r
235   pos_d.y2 = 30;\r
236   pos_d.x3 = 60;\r
237   pos_d.y3 = 90;\r
238   pos_d.x4 = 120;\r
239   pos_d.y4 = 150;\r
240 */\r
241 \r
242   if (ioctl(fdVideo, AV_SET_VID_POSITION, &pos_d) != 0) return 0;\r
243   return 1;\r
244 }\r
245 \r
246 int VideoMVP::sync()\r
247 {\r
248   if (!initted) return 0;\r
249 \r
250   if (ioctl(fdVideo, AV_SET_VID_SYNC, 2) != 0) return 0;\r
251   return 1;\r
252 }\r
253 \r
254 int VideoMVP::play()\r
255 {\r
256   if (!initted) return 0;\r
257 \r
258   if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
259   return 1;\r
260 }\r
261 \r
262 int VideoMVP::stop()\r
263 {\r
264   if (!initted) return 0;\r
265 \r
266   if (ioctl(fdVideo, AV_SET_VID_STOP, 0) != 0) return 0;\r
267   return 1;\r
268 }\r
269 \r
270 int VideoMVP::reset()\r
271 {\r
272   if (!initted) return 0;\r
273 \r
274   if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0;\r
275   return 1;\r
276 }\r
277 \r
278 int VideoMVP::pause()\r
279 {\r
280   if (!initted) return 0;\r
281 \r
282   if (ioctl(fdVideo, AV_SET_VID_PAUSE, 0) != 0) return 0;\r
283   return 1;\r
284 }\r
285 \r
286 int VideoMVP::unPause() // FIXME get rid - same as play!!\r
287 {\r
288   if (!initted) return 0;\r
289   if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
290   return 1;\r
291 }\r
292 \r
293 int VideoMVP::fastForward()\r
294 {\r
295   if (!initted) return 0;\r
296 \r
297   if (ioctl(fdVideo, AV_SET_VID_FFWD, 1) != 0) return 0;\r
298   return 1;\r
299 }\r
300 \r
301 int VideoMVP::unFastForward()\r
302 {\r
303   if (!initted) return 0;\r
304 \r
305 //  if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0; // don't need this.\r
306 \r
307   if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
308   return 1;\r
309 }\r
310 \r
311 int VideoMVP::attachFrameBuffer()\r
312 {\r
313   if (!initted) return 0;\r
314 \r
315   if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;\r
316   return 1;\r
317 }\r
318 \r
319 int VideoMVP::blank(void)\r
320 {\r
321   if (ioctl(fdVideo, AV_SET_VID_FB, 1) != 0) return 0;\r
322   if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;\r
323   return 1;\r
324 }\r
325 \r
326 ULLONG VideoMVP::getCurrentTimestamp()\r
327 {\r
328   sync_data_t timestamps;\r
329   if (ioctl(fdVideo, AV_GET_VID_TIMESTAMPS, &timestamps) == 0)\r
330   {\r
331     // FIXME are these the right way around?\r
332 \r
333     timestamps.stc = (timestamps.stc >> 31 ) | (timestamps.stc & 1);\r
334     timestamps.pts = (timestamps.pts >> 31 ) | (timestamps.pts & 1);\r
335 \r
336     return timestamps.stc;\r
337   }\r
338   else\r
339   {\r
340     return 0;\r
341   }\r
342 }\r
343 \r
344 ULONG VideoMVP::timecodeToFrameNumber(ULLONG timecode)\r
345 {\r
346   if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);\r
347   else               return (ULONG)(((double)timecode / (double)90000) * (double)30);\r
348 }\r
349 \r
350 #ifdef DEV\r
351 int VideoMVP::test()\r
352 {\r
353   return 0;\r
354 \r
355 //  ULLONG stc = 0;\r
356 //  return ioctl(fdVideo, AV_SET_VID_STC, &stc);\r
357 /*\r
358  // reset();\r
359   return 1;\r
360 */\r
361 }\r
362 \r
363 int VideoMVP::test2()\r
364 {\r
365   return 0;\r
366 }\r
367 #endif\r
368 \r
369 void VideoMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)\r
370 {\r
371   MediaPacketList::const_iterator iter = mplist.begin();\r
372   deliver_start = iter->pos_buffer + samplepos;\r
373   mediapacket_len[0] = deliver_length = iter->length;\r
374   deliver_count = 1;\r
375   while (++iter != mplist.end() &&\r
376            iter->pos_buffer == deliver_start + deliver_length)\r
377   {\r
378     deliver_length += iter->length;\r
379     mediapacket_len[deliver_count] = iter->length;\r
380     ++deliver_count;\r
381     if (deliver_length >= WRITE_LENGTH ||\r
382         deliver_count == WRITE_PACKETS) break;\r
383   }\r
384 }\r
385 \r
386 UINT VideoMVP::DeliverMediaSample(UCHAR* buffer, UINT* samplepos)\r
387 {\r
388   int written = ::write(fdVideo, buffer + deliver_start, deliver_length);\r
389   if (written == (int)deliver_length) { *samplepos = 0; return deliver_count;}\r
390   if (written <= 0) return 0;\r
391   // Handle a partial write. Is this possible? Should we bother?\r
392   UINT i = 0;\r
393   while ((written -= mediapacket_len[i]) >= 0) i++;\r
394   *samplepos = mediapacket_len[i] + written;\r
395   return i;\r
396 }\r
397 \r
398 void VideoMVP::ResetTimeOffsets()\r
399 {\r
400 }\r
401 \r
402 bool VideoMVP::displayIFrame(const UCHAR* buffer, UINT length)\r
403 {\r
404   write(fdVideo, buffer, length);\r
405   return true;\r
406 }\r