Annotation of margi2/video.c, revision 1.3
1.1 cvs 1: /*
2: video.c
3:
4: Copyright (C) Christian Wolff for convergence integrated media.
5:
6: This program is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 2 of the License, or
9: (at your option) any later version.
10:
11: This program is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with this program; if not, write to the Free Software
18: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19: */
20:
21: //
22: // Video Decoder
23: //
24: #define __NO_VERSION__
25:
26: #include "video.h"
27: #include "l64021.h"
28: #include "dram.h"
29:
30: // Set the background of the OSD and SPU and it's color
31: // mode=0: Video on Black
32: // mode=1: Black
33: // mode=2: Selected Color
34: // mode=3: Video on Selected Color
35: void VideoSetBackground(struct cvdv_cards *card, int mode, u8 Y, u8 Cb,
36: u8 Cr)
37: {
38: DecoderWriteByte(card, 0x10A, Y);
39: DecoderWriteByte(card, 0x10B, Cb);
40: DecoderWriteByte(card, 0x10C, Cr);
41: DecoderMaskByte(card, 0x109, 0xC0, mode << 6);
42: }
43:
44:
45: int DecoderStartDecode(struct cvdv_cards *card)
46: {
47: DecoderSetByte(card, 0x0F6, 0x01);
1.3 ! mocm 48: if (card->audiostate.AVSyncState)
! 49: card->videosync = 1;
1.1 cvs 50: return 0;
51: }
52:
53: int DecoderStopDecode(struct cvdv_cards *card)
54: {
55: DecoderDelByte(card, 0x0F6, 0x01);
56: card->videosync = 0;
57: return 0;
58: }
59:
60: // Sets Display Override (Still Image Display) to Frame Buffer at specified addresses,
61: // addresses are 16 bit, in 64 byte resolution
62: // mode: 0=off, 1=Frame, 2=Field
63: // width: width of the still picture in 8 pixel units
64: int DecoderStillImageDisplay(struct cvdv_cards *card, int mode, int width,
65: u16 LumaAddr, u16 ChromaAddr)
66: {
67: DecoderStopDecode(card);
68: DecoderWriteWord(card, 0x11D, LumaAddr);
69: DecoderWriteWord(card, 0x11F, ChromaAddr);
70: DecoderWriteByte(card, 0x11B, width & 0x7F);
71: DecoderMaskByte(card, 0x109, 0x30, (mode & 3) << 4); // Display Override Mode
72: return 0;
73: }
74:
75: // Frees allocated frame buffers
76: int DecoderKillFrameBuffers(struct cvdv_cards *card)
77: {
78: printk(KERN_DEBUG LOGNAME ": -- DecoderKillFrameBuffers\n");
79: DecoderStopDecode(card);
80: DRAMFree(card, card->FrameStoreLuma1);
81: card->FrameStoreLuma1 = BLANK;
82: DRAMFree(card, card->FrameStoreChroma1);
83: card->FrameStoreChroma1 = BLANK;
84: DRAMFree(card, card->FrameStoreLuma2);
85: card->FrameStoreLuma2 = BLANK;
86: DRAMFree(card, card->FrameStoreChroma2);
87: card->FrameStoreChroma2 = BLANK;
88: DRAMFree(card, card->FrameStoreLumaB);
89: card->FrameStoreLumaB = BLANK;
90: DRAMFree(card, card->FrameStoreChromaB);
91: card->FrameStoreChromaB = BLANK;
92: card->FrameBuffersAllocated = 0;
93: // DecoderWriteWord(
94: return 0;
95: }
96:
97: int DecoderSetFrameBuffers(struct cvdv_cards *card, int lines, // number of lines of the decoded MPEG
98: int TwoFrames, // 1 if no B-Frames are present in the video stream, thus allowing only 2 framestores
99: int RMM) // 1 if RMM
100: {
101: #define SEGMENTS 44 // 40..54 for PAL, 44 recommended
102: #define BUFFERSET(buf,adr,align) if (buf>0) {\
103: if (buf&((1<<align)-1)) buf=(buf&~((1<<align)-1))+(1<<align);\
104: addr=DRAMAlloc(card,buf,1<<align);\
105: if (addr==BLANK) return adr;\
106: card->buf=addr;\
107: addr>>=align;\
108: DecoderWriteByte(card,adr,addr&0xFF);\
109: DecoderWriteByte(card,adr+1,(addr>>8)&(0x00FF));\
110: }
111: u32 addr;
112: int pixel, byteperline; // visible pixel per video line, same for PAL and NTSC
113: int FrameStoreLuma1, FrameStoreChroma1,
114: FrameStoreLuma2, FrameStoreChroma2,
115: FrameStoreLumaB, FrameStoreChromaB;
116: printk(KERN_DEBUG LOGNAME ": -- DecoderSetFrameBuffers\n");
117: DecoderStopDecode(card);
118: //DecoderStopChannel(card);
119: //lines=((CCIR601Lines(card->videomode)==625)?576:480);
120: byteperline = (DecoderReadByte(card, 0x116) & 0x7F) * 8; // main 64-bit reads per line
121: pixel = byteperline * lines;
122: FrameStoreLuma1 = FrameStoreLuma2 = FrameStoreLumaB = pixel >> 1; // 8 bit luma per pixel in words
123: FrameStoreChroma1 = FrameStoreChroma2 = FrameStoreChromaB =
124: pixel >> 2; // 8+8 bit chroma every 2nd pixel every 2nd line
125: if (card->FrameBuffersAllocated)
126: DecoderKillFrameBuffers(card);
127: BUFFERSET(FrameStoreLuma1, 0x0E0, 5); // Anchor Frame Store 1
128: BUFFERSET(FrameStoreChroma1, 0x0E2, 5);
129: BUFFERSET(FrameStoreLuma2, 0x0E4, 5); // Anchor Frame Store 2
130: BUFFERSET(FrameStoreChroma2, 0x0E6, 5);
131: if (TwoFrames) {
132: DecoderDelByte(card, 0x0F8, 0x01);
133: } else {
134: // if (CCIR601Lines(card->videomode)==525) { // Normal Mode, NTSC
135: if (!RMM) { // Normal Mode, NTSC
136: BUFFERSET(FrameStoreLumaB, 0x0E8, 5); // B Frame Store
137: BUFFERSET(FrameStoreChromaB, 0x0EA, 5);
138: DecoderDelByte(card, 0x0F8, 0x01);
139: } else { // Reduced Memory Mode, PAL
140: // 44 segments with 8 lines each (8 bit luma + 4 bit chroma)
141: // only display modes 4-8, 10, and 11 are allowed
142: FrameStoreLumaB =
143: (8 * byteperline * SEGMENTS) >> 1;
144: FrameStoreChromaB =
145: (4 * byteperline * SEGMENTS) >> 1;
146: BUFFERSET(FrameStoreLumaB, 0x0E8, 5); // B Frame Store
147: BUFFERSET(FrameStoreChromaB, 0x0EA, 5);
148: DecoderWriteByte(card, 0x121, SEGMENTS << 1); // Number of segments
149: DecoderSetByte(card, 0x0F8, 0x01);
150: }
151: }
152: card->FrameBuffersAllocated = 1;
153: #undef SEGMENTS
154: #undef BUFFERSET
155: return 0;
156: }
157:
158: // returns size of the Video ES Buffer in bytes or 0=error
159: u32 DecoderGetVideoESSize(struct cvdv_cards * card)
160: {
161: if (!card->ChannelBuffersAllocated)
162: return 0; // buffer not initialised
163: return (u32) ((DecoderReadWord(card, 0x04A) & 0x3FFF) -
164: (DecoderReadWord(card, 0x048) & 0x3FFF)) * 256; // bytes
165: }
166:
167: // returns level of fullness in bytes
168: u32 DecoderGetVideoESLevel(struct cvdv_cards * card)
169: {
170: u32 items;
171: items = DecoderReadByte(card, 0x086);
172: items |= ((DecoderReadWord(card, 0x087) & 0x07FF) << 8);
173: items *= 8; // 64 bit per item
174: return items;
175: }
176:
177: // pics=0 --> items=bytes
178: // pics=1 --> items=pictures
179: void DecoderSetVideoPanic(struct cvdv_cards *card, int pics, int items)
180: {
181: if (pics < 0) {
182: DecoderMaskByte(card, 0x045, 0x18, 0x00 << 3); // disable panic mode
183: } else {
184: if (pics) {
185: DecoderWriteMWord(card, 0x086, items & 0x0003FFFF);
186: DecoderMaskByte(card, 0x045, 0x18, 0x02 << 3); // set panic mode to "number of pictures" in VideoES
187: } else {
188: DecoderWriteMWord(card, 0x086,
189: (items / 8) & 0x0003FFFF);
190: DecoderMaskByte(card, 0x045, 0x18, 0x01 << 3); // set panic mode to "number of 8-byte-frames" in VideoES
191: }
192: }
193: }
194:
195: int DecoderClose(struct cvdv_cards *card)
196: {
197: if (card->DecoderOpen) {
198: printk(KERN_DEBUG LOGNAME ": -- DecoderClose\n");
199: DecoderStopDecode(card);
200: DecoderKillFrameBuffers(card);
201: card->DecoderOpen = 0;
202: card->lastvattr = 0;
203: return 0;
204: } else
205: return 1;
206: }
207:
208: // returns 0 on success, 1 on "picture size too big", 2 on "out of DRAM memory"
209: int DecoderOpen(struct cvdv_cards *card, int x, int y, // size of the decoded MPEG picture
210: int aspect, // pixel or picture aspect ratio of the MPEG picture: 1=square pixel 2=3:4 3=9:16 4=1:2.21
211: int Field, // 0:Frame (interlaced, MPEG-2) , 1:Field (non-interlaced, MPEG-1) structure
212: int Letterbox, // 0:PanScan (4:3), 1:letterbox (16:9, 8:3) picture ratio
213: int RMM) // 1:use ReducedMemoryMode
214: {
215: int mode, // Display Mode
216: i, factor, // zoom factor
217: top, bottom, left, right, width, height, newwidth, newheight, // screen size
218: vaspx, vaspy, // output video pixel aspect ratio
219: paspx, paspy, // input picture pixel aspect ratio
220: SIF; // 0:Full (480/576 lines, MPEG-2), 1:SIF (half, 240/288 lines, MPEG-1) resolution
221:
222: printk(KERN_DEBUG LOGNAME
223: ": -- DecoderOpen x:%d y:%d asp:%d field:%d lt:%d rmm:%d\n",
224: x, y, aspect, Field, Letterbox, RMM);
225: if ((x <= 0) || (y <= 0))
226: return 4; // picture too small
227: //if (card->DecoderOpen) return 3;
228: DecoderStopDecode(card);
229: DecoderClose(card); // closes only, if already open
230: vaspy = 11;
231: vaspx = ((CCIR601Lines(card->videomode) == 525) ? 10 : 12); // screen pixel aspect ratio
232: // note: this aspect ratio applies to 704 pixel width, but the card's default is 720, wich is not 3:4 picture aspect ratio anymore!?
233: i = ((x == 720) ? 704 : x); // 720 wide is overscan of 704 wide
234: switch (aspect) { // MPEG data pixel aspect ratio
235: case 1:
236: paspx = 1;
237: paspy = 1;
238: break;
239: default:
240: case 2:
241: paspx = 4 * y;
242: paspy = 3 * i;
243: break;
244: case 3:
245: paspx = 16 * y;
246: paspy = 9 * i;
247: break;
248: case 4:
249: paspx = 221 * y;
250: paspy = 100 * i;
251: break;
252: }
253: top =
254: DecoderReadByte(card,
255: 0x129) | ((DecoderReadByte(card, 0x12B) & 0x07)
256: << 8); // current Start- and End Column
257: bottom =
258: DecoderReadByte(card,
259: 0x12A) | ((DecoderReadByte(card, 0x12B) & 0x70)
260: << 4);
261: height = (bottom - top + 1) * 2; // screen (frame) height
262: left =
263: DecoderReadByte(card,
264: 0x12C) | ((DecoderReadByte(card, 0x12E) & 0x07)
265: << 8); // current Start- and End Row
266: right =
267: DecoderReadByte(card,
268: 0x12D) | ((DecoderReadByte(card, 0x12E) & 0x70)
269: << 4);
270: width = (right - left + 1) / 2; // screen width, 2 clocks = 1 pixel
271:
272: if (RMM)
273: DecoderSetByte(card, 0x0F8, 0x01);
274: else
275: DecoderDelByte(card, 0x0F8, 0x01);
1.2 rjkm 276:
1.1 cvs 277: DecoderWriteByte(card, 0x0EF, 0x08);
278:
279: //if (x>width) { // Is the picture too wide for the screen?
280: // DecoderSetByte(card,0x112,0x40); // Horiz. 2:1 Filter enable
281: // x/=2;
282: //} else {
283: DecoderDelByte(card, 0x112, 0x40); // Horiz. 2:1 Filter disable
284: //}
285:
286:
287:
288:
289: if (1 /*Letterbox */ ) { // Fit to width, reduce height
290: newwidth = (x * vaspy * paspx / (paspy * vaspx)); // width in right aspect ratio
291: if (newwidth <= 360) { // less then about half the screen size?
292: SIF = 1;
293: newwidth *= 2;
294: } else {
295: SIF = 0;
296: }
297: if ((newwidth == 704) || (newwidth == 720))
298: width = newwidth; // standard sizes?
299: newheight =
300: (y * vaspx * paspy / (paspx * vaspy)) * width / x;
301: factor = newheight * 100 / y;
302: printk(KERN_INFO LOGNAME
303: ": Decoder Open: Display size %d x %d, Picture size %d x %d, Demanded size: %d x %d, factor %d\n",
304: width, height, x, y, newwidth, newheight, factor);
305: // 16:9 Letterbox
306: if ((aspect == 3)
307: || ((aspect == 0)
308: && (((factor >= 65) && (factor <= 80))
309: || ((factor >= 140) && (factor <= 160))))) {
310: if (SIF) { // height * 1.5, SIF Letterbox
311: if (RMM)
312: return 1; // not supported!
313: height = (y * 3) / 2 - 2;
314: mode = 3;
315: } else { // height * 0.75, 16:9 Letterbox
316: height = (y * 3) / 4 - 2;
317: mode = 8;
318: }
319: // 2.21:1 Letterbox
320: } else if ((aspect == 4)
321: || ((aspect == 0)
322: && (((factor >= 45) && (factor <= 60))
323: || (SIF && ((factor >= 90)
324: && (factor <= 110)))))) {
325: if (SIF) { // height * 1
326: height = y;
327: mode = 5;
328: } else { // height / 2
329: height = y / 2;
330: mode = 11;
331: }
332: // 3:4 aspect ratio
333: } else {
334: if (SIF) {
335: height = y * 2;
336: mode = ((Field && ~RMM) ? 9 : 10);
337: } else if (newwidth > 720) { // picture too wide, scale down to 3/4
338: height = (y * 3) / 4;
339: mode = 8;
340: } else {
341: height = y;
342: mode = ((Field) ? 7 : 5);
343: // mode=((Field)?5:7);
344: }
345: }
346: width = (x * vaspy * paspx / (paspy * vaspx)) * height / y;
347: if (x < width) { // does the picture needs a horizontal blow-up?
348: DecoderWriteByte(card, 0x115,
349: ((x * 256 + width - 1) / width) & 0xFF); // Horiz.Filter scale, x/width*256, rounded up
350: DecoderSetByte(card, 0x114, 0x02); // Horiz.Filter enable
351: } else if (x == width) {
352: DecoderWriteByte(card, 0x115, 0); // 1:1 scale
353: DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable
354: } else if (x <= 720) {
355: width = x;
356: DecoderWriteByte(card, 0x115, 0); // 1:1 scale
357: DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable
358: } else { // picture is more than twice the screen width. sigh.
359: return 1;
360: }
361: } else { // Pan-Scan, fit height to maximum
362: DecoderSetByte(card, 0x117, 0x40); // pan-scan from bitstream
363: //TODO
364: newwidth = (x * vaspy * paspx / (paspy * vaspx)); // width in right aspect ratio
365: newheight = y;
366: if (newheight <= 288) { // less then about half the screen size?
367: SIF = 1;
368: newheight *= 2;
369: } else {
370: SIF = 0;
371: }
372: if ((newwidth == 704) || (newwidth == 720))
373: width = newwidth; // standard sizes?
374: //newheight=(y*vaspx*paspy/(paspx*vaspy))*width/x;
375: factor = newheight * 100 / y;
376: printk(KERN_INFO LOGNAME
377: ": Decoder Open: Display size %d x %d, Picture size %d x %d, Demanded size: %d x %d, factor %d\n",
378: width, height, x, y, newwidth, newheight, factor);
379: if (aspect == 3) { // 16:9 Letterbox
380: if (SIF) { // height * 1.5, SIF Letterbox
381: if (RMM)
382: return 1; // not supported!
383: height = (y * 3) / 2;
384: mode = 3;
385: } else { // height * 0.75, 16:9 Letterbox
386: height = (y * 3) / 4;
387: mode = 8;
388: }
389: } else if (aspect == 4) { // 2.21:1 Letterbox
390: if (SIF) { // height * 1
391: height = y;
392: mode = 5;
393: } else { // height / 2
394: height = y / 2;
395: mode = 11;
396: }
397: } else if (aspect == 2) { // 3:4 aspect ratio
398: if (SIF) {
399: height = y * 2;
400: mode = ((Field && ~RMM) ? 9 : 10);
401: } else if (newwidth > 720) { // picture too wide, scale down to 3/4
402: height = (y * 3) / 4;
403: mode = 8;
404: } else {
405: height = y;
406: mode = ((Field) ? 7 : 5);
407: // mode=((Field)?5:7);
408: }
409: }
410: width = (x * vaspy * paspx / (paspy * vaspx)) * height / y;
411: if (x < width) { // does the picture needs a horizontal blow-up?
412: DecoderWriteByte(card, 0x115,
413: ((x * 256 + width - 1) / width) & 0xFF); // Horiz.Filter scale, x/width*256, rounded up
414: DecoderSetByte(card, 0x114, 0x02); // Horiz.Filter enable
415: } else if (x == width) {
416: DecoderWriteByte(card, 0x115, 0); // 1:1 scale
417: DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable
418: } else if (x <= 720) {
419: width = x;
420: DecoderWriteByte(card, 0x115, 0); // 1:1 scale
421: DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable
422: } else { // picture is more than twice the screen width. sigh.
423: return 1;
424: }
425: }
426: printk(KERN_INFO LOGNAME
427: ": Decoder Open: Display size %d x %d, Picture size %d x %d Mode: %d\n",
428: width, height, x, y, mode);
429:
430: // calculate new picture start- and end rows and columns
431: height /= 2; // convert back to field height
432: top += ((bottom - top + 1 - height) / 2);
433: if (top < 0)
434: top = 0;
435: bottom = top + height - 1;
436: width *= 2; // convert back to clocks
437: left += ((right - left + 1 - width) / 2);
438: if (left < 0)
439: left = 0;
440: right = left + width - 1;
441: DecoderWriteByte(card, 0x12C, left & 0xFF); // Start- and End Column
442: DecoderWriteByte(card, 0x12D, right & 0xFF);
443: DecoderWriteByte(card, 0x12E,
444: ((right >> 4) & 0x70) | ((left >> 8) & 0x07));
445: DecoderWriteByte(card, 0x129, top & 0xFF); // Start- and End Row
446: DecoderWriteByte(card, 0x12A, bottom & 0xFF);
447: DecoderWriteByte(card, 0x12b,
448: ((bottom >> 4) & 0x70) | ((top >> 8) & 0x07));
449:
450: DecoderWriteByte(card, 0x116, ((x + 7) / 8) & 0x7F); // Main Reads per Line
451:
452: // set the new mode
453: DecoderMaskByte(card, 0x114, 0x78, (mode & 0x0F) << 3);
454:
455: //printk(KERN_INFO LOGNAME ": Decoder Open: top/bottom/width / left/right/height / main reads %d/%d/%d / %d/%d/%d / %d\n",top,bottom,width,left,right,height,((x+7)/8)&0x7F);
456:
457: // set the frame store buffers
458: if ((i = DecoderSetFrameBuffers(card, y, 0, RMM))) {
459: printk(KERN_ERR LOGNAME
460: ": SetFrameBuffers failed for buffer at 0x%03X\n",
461: i);
462: DecoderKillFrameBuffers(card);
463: return 2;
464: }
465:
466: card->lastvattr = 0;
467: card->DecoderOpen = 1;
468: return 0;
469: }
470:
471: // displays a still image, whose pixel data is in luma and chroma
472: int DecoderShowStill(struct cvdv_cards *card, int width, int height,
473: u8 * luma, u8 * chroma)
474: {
475: u16 addr;
476: DecoderOpen(card, width, height,
477: (((width == 320) || (width == 640) || (width == 384)
478: || (width == 768)) ? 1 : 2),
479: ((height < 313) ? 1 : 0), 1, 0);
480: addr =
481: ((DecoderReadWord(card, 0x11D) == DecoderReadWord(card, 0x0E0))
482: ? 0x0E4 : 0x0E0); // choose invisible frame
483: DRAMWriteByte(card, DecoderReadWord(card, addr) << 5,
484: width * height, luma, 1);
485: DRAMWriteByte(card, DecoderReadWord(card, addr + 2) << 5,
486: width * height / 2, chroma, 1);
487: DecoderStillImageDisplay(card, ((height < 313) ? 2 : 1),
488: DecoderReadByte(card, 0x116) & 0x7F,
489: DecoderReadWord(card, addr),
490: DecoderReadWord(card, addr + 2));
491: VideoSetBackground(card, 0, 0, 0, 0); // video on black
492: return 0;
493: }
494:
495: // TODO: untested, probably won't work (have to use "main reads per line" instead of width on SIF)
496: int DecoderGetStill(struct cvdv_cards *card, int *width, int *height,
497: u8 * luma, u8 * chroma)
498: {
499: int framebuffer;
500: if (card->DecoderOpen) {
501: //*width=((DecoderReadByte(card,0x12D)|((DecoderReadByte(card,0x12E)&0x70)<<4))-(DecoderReadByte(card,0x12C)|((DecoderReadByte(card,0x12E)&0x07)<<8))+1)/2; // screen width, 2 clocks = 1 pixel
502: *width = DecoderReadByte(card, 0x116) * 8;
503: *height =
504: ((DecoderReadByte
505: (card,
506: 0x12A) | ((DecoderReadByte(card, 0x12B) & 0x70) <<
507: 4)) -
508: (DecoderReadByte(card, 0x129) |
509: ((DecoderReadByte(card, 0x12B) & 0x07) << 8)) + 1) * 2; // screen (frame) height
510: if ((luma != NULL) && (chroma != NULL)) {
511: framebuffer =
512: (((DecoderReadByte(card, 0x0EE) & 0x0C) == 1) ?
513: 0x0E4 : 0x0E0);
514: DRAMReadByte(card,
515: DecoderReadWord(card,
516: framebuffer) << 5,
517: (*width) * (*height), luma, 1);
518: DRAMReadByte(card,
519: DecoderReadWord(card,
520: framebuffer + 2) << 5,
521: (*width) * (*height) / 2, chroma, 1);
522: }
523: return 0;
524: } else
525: return 1;
526: }
LinuxTV legacy CVS <linuxtv.org/cvs>