readv210.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * readV210.c - read single uncompressed Quicktime YUV image.
  3. * http://developer.apple.com/quicktime/icefloe/dispatch019.html#v210
  4. * Steve Simon, 2009
  5. */
  6. #include <u.h>
  7. #include <libc.h>
  8. #include <bio.h>
  9. #include <draw.h>
  10. #include <ctype.h>
  11. #include "imagefile.h"
  12. enum {
  13. Pixels = 720,
  14. R601pal = 576,
  15. R601ntsc = 486,
  16. Shift = 13
  17. };
  18. static int
  19. looksize(char *file, vlong size, int *pixels, int *lines, int *chunk)
  20. {
  21. Biobuf *bp;
  22. uvlong l, p, c;
  23. char *s, *a[12];
  24. /*
  25. * This may not always work, there could be an alias between file
  26. * sizes of different standards stored in 8bits and 10 bits.
  27. */
  28. if((bp = Bopen(file, OREAD)) == nil)
  29. return -1;
  30. while((s = Brdstr(bp, '\n', 1)) != nil){
  31. if(tokenize(s, a, nelem(a)) < 3)
  32. continue;
  33. if(a[0][0] == '#')
  34. continue;
  35. p = atoll(a[3]);
  36. l = atoll(a[5]);
  37. l += atoll(a[7]);
  38. c = 128 * ceil(p/48);
  39. if(l*c == size){
  40. *pixels = p;
  41. *lines = l;
  42. *chunk = c;
  43. break;
  44. }
  45. }
  46. Bterm(bp);
  47. if(s == nil)
  48. return -1;
  49. return 0;
  50. }
  51. static int
  52. clip(int x)
  53. {
  54. x >>= Shift + 2; /* +2 as we assume all input images are 10 bit */
  55. if(x > 255)
  56. return 0xff;
  57. if(x <= 0)
  58. return 0;
  59. return x;
  60. }
  61. Rawimage**
  62. BreadV210(Biobuf *bp, int colourspace)
  63. {
  64. Dir *d;
  65. uvlong sz;
  66. Rawimage *a, **array;
  67. ushort *mux, *end, *frm, *wr;
  68. uchar *buf, *r, *g, *b;
  69. uint i, t;
  70. int y1, y2, cb, cr, c, l, rd;
  71. int chunk, lines, pixels;
  72. int F1, F2, F3, F4;
  73. buf = nil;
  74. if(colourspace != CYCbCr){
  75. werrstr("BreadV210: unknown colour space %d", colourspace);
  76. return nil;
  77. }
  78. if((d = dirfstat(Bfildes(bp))) != nil){
  79. sz = d->length;
  80. free(d);
  81. }
  82. else {
  83. fprint(2, "cannot stat input, assuming pixelsx576x10bit\n");
  84. sz = Pixels * R601pal * 2L + (pixels * R601pal / 2L);
  85. }
  86. if(looksize("/lib/video.specs", sz, &pixels, &lines, &chunk) == -1){
  87. werrstr("file spec not in /lib/video.specs\n");
  88. return nil;
  89. }
  90. if((a = calloc(sizeof(Rawimage), 1)) == nil)
  91. sysfatal("no memory");
  92. if((array = calloc(sizeof(Rawimage * ), 2)) == nil)
  93. sysfatal("no memory");
  94. array[0] = a;
  95. array[1] = nil;
  96. a->nchans = 3;
  97. a->chandesc = CRGB;
  98. a->chanlen = pixels * lines;
  99. a->r = Rect(0, 0, pixels, lines);
  100. if((frm = malloc(pixels*2*lines*sizeof(ushort))) == nil)
  101. goto Error;
  102. for(c = 0; c < 3; c++)
  103. if((a->chans[c] = malloc(pixels*lines)) == nil)
  104. goto Error;
  105. if((buf = malloc(chunk)) == nil)
  106. goto Error;
  107. for(l = 0; l < lines; l++){
  108. if(Bread(bp, buf, chunk) == -1)
  109. goto Error;
  110. rd = 0;
  111. wr = &frm[l*pixels*2];
  112. end = &frm[(l+1)*pixels*2];
  113. while(wr < end){
  114. t = 0;
  115. for(i = 0; i < 4; i++)
  116. t += buf[rd+i] << 8*i;
  117. *wr++ = t & 0x3ff;
  118. *wr++ = t>>10 & 0x3ff;
  119. *wr++ = t>>20 & 0x3ff;
  120. rd += 4;
  121. }
  122. }
  123. mux = frm;
  124. end = frm + pixels * lines * 2;
  125. r = a->chans[0];
  126. g = a->chans[1];
  127. b = a->chans[2];
  128. if(pixels == Pixels && lines != R601pal){ // 625
  129. F1 = floor(1.402 * (1 << Shift));
  130. F2 = floor(0.34414 * (1 << Shift));
  131. F3 = floor(0.71414 * (1 << Shift));
  132. F4 = floor(1.772 * (1 << Shift));
  133. }
  134. else{ // 525 and HD
  135. F1 = floor(1.5748 * (1 << Shift));
  136. F2 = floor(0.1874 * (1 << Shift));
  137. F3 = floor(0.4681 * (1 << Shift));
  138. F4 = floor(1.8560 * (1 << Shift));
  139. }
  140. /*
  141. * Fixme: fixed colourspace conversion at present
  142. */
  143. while(mux < end){
  144. cb = *mux++ - 512;
  145. y1 = (int)*mux++ << Shift;
  146. cr = *mux++ - 512;
  147. y2 = (int)*mux++ << Shift;
  148. *r++ = clip(y1 + F1*cr);
  149. *g++ = clip(y1 - F2*cb - F3*cr);
  150. *b++ = clip((y1 + F4*cb));
  151. *r++ = clip(y2 + F1*cr);
  152. *g++ = clip(y2 - F2*cb - F3*cr);
  153. *b++ = clip((y2 + F4*cb));
  154. }
  155. free(frm);
  156. free(buf);
  157. return array;
  158. Error:
  159. for(c = 0; c < 3; c++)
  160. free(a->chans[c]);
  161. free(a->cmap);
  162. free(array[0]);
  163. free(array);
  164. free(frm);
  165. free(buf);
  166. return nil;
  167. }
  168. Rawimage**
  169. readV210(int fd, int colorspace)
  170. {
  171. Rawimage * *a;
  172. Biobuf b;
  173. if(Binit(&b, fd, OREAD) < 0)
  174. return nil;
  175. a = BreadV210(&b, colorspace);
  176. Bterm(&b);
  177. return a;
  178. }