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