quicktime.b 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. implement QuickTime;
  2. include "sys.m";
  3. sys: Sys;
  4. include "quicktime.m";
  5. init()
  6. {
  7. sys = load Sys Sys->PATH;
  8. }
  9. open(file: string): (ref QD, string)
  10. {
  11. fd := sys->open(file, sys->OREAD);
  12. if(fd == nil)
  13. return (nil, "open failed");
  14. r := ref QD;
  15. r.fd = fd;
  16. r.buf = array[DEFBUF] of byte;
  17. (hdr, l) := r.atomhdr();
  18. if(hdr != "mdat")
  19. return (nil, "not a QuickTime movie file");
  20. #
  21. # We are expecting a unified file with .data then .rsrc
  22. #
  23. r.skipatom(l);
  24. return (r, nil);
  25. }
  26. QD.atomhdr(r: self ref QD): (string, int)
  27. {
  28. b := array[8] of byte;
  29. if(r.readn(b, 8) != 8)
  30. return (nil, -1);
  31. for(i := 0; i < 8; i++)
  32. sys->print("%.2ux ", int b[i]);
  33. sys->print(" %s %d\n", string b[4:8], bedword(b, 0));
  34. return (string b[4:8], bedword(b, 0));
  35. }
  36. QD.skipatom(r: self ref QD, l: int): int
  37. {
  38. return r.skip(l - AtomHDR);
  39. }
  40. QD.mvhd(q: self ref QD, l: int): string
  41. {
  42. l -= AtomHDR;
  43. if(l != MvhdrSIZE)
  44. return "mvhd atom funny size";
  45. b := array[l] of byte;
  46. if(q.readn(b, l) != l)
  47. return "short read in mvhd";
  48. mvhdr := ref Mvhdr;
  49. mvhdr.version = bedword(b, 0);
  50. mvhdr.create = bedword(b, 4);
  51. mvhdr.modtime = bedword(b, 8);
  52. mvhdr.timescale = bedword(b, 12);
  53. mvhdr.duration = bedword(b, 16);
  54. mvhdr.rate = bedword(b, 20);
  55. mvhdr.vol = beword(b, 24);
  56. mvhdr.r1 = bedword(b, 26);
  57. mvhdr.r2 = bedword(b, 30);
  58. mvhdr.matrix = array[9] of int;
  59. for(i :=0; i<9; i++)
  60. mvhdr.matrix[i] = bedword(b, 34+i*4);
  61. mvhdr.r3 = beword(b, 70);
  62. mvhdr.r4 = bedword(b, 72);
  63. mvhdr.pvtime = bedword(b, 76);
  64. mvhdr.posttime = bedword(b, 80);
  65. mvhdr.seltime = bedword(b, 84);
  66. mvhdr.seldurat = bedword(b, 88);
  67. mvhdr.curtime = bedword(b, 92);
  68. mvhdr.nxttkid = bedword(b, 96);
  69. q.mvhdr = mvhdr;
  70. return nil;
  71. }
  72. QD.trak(q: self ref QD, l: int): string
  73. {
  74. (tk, tkl) := q.atomhdr();
  75. if(tk != "tkhd")
  76. return "missing track header atom";
  77. l -= tkl;
  78. tkl -= AtomHDR;
  79. b := array[tkl] of byte;
  80. if(q.readn(b, tkl) != tkl)
  81. return "short read in tkhd";
  82. tkhdr := ref Tkhdr;
  83. tkhdr.version = bedword(b, 0);
  84. tkhdr.creation = bedword(b, 4);
  85. tkhdr.modtime = bedword(b, 8);
  86. tkhdr.trackid = bedword(b, 12);
  87. tkhdr.timescale = bedword(b, 16);
  88. tkhdr.duration = bedword(b, 20);
  89. tkhdr.timeoff = bedword(b, 24);
  90. tkhdr.priority = bedword(b, 28);
  91. tkhdr.layer = beword(b, 32);
  92. tkhdr.altgrp = beword(b, 34);
  93. tkhdr.volume = beword(b, 36);
  94. tkhdr.matrix = array[9] of int;
  95. for(i := 0; i < 9; i++)
  96. tkhdr.matrix[i] = bedword(b, 38+i*4);
  97. tkhdr.width = bedword(b, 74);
  98. tkhdr.height = bedword(b, 78);
  99. (md, mdl) := q.atomhdr();
  100. if(md != "mdia")
  101. return "missing media atom";
  102. while(mdl != AtomHDR) {
  103. (atom, atoml) := q.atomhdr();
  104. sys->print("\t%s %d\n", atom, atoml);
  105. q.skipatom(atoml);
  106. mdl -= atoml;
  107. }
  108. return nil;
  109. }
  110. QD.readn(r: self ref QD, b: array of byte, l: int): int
  111. {
  112. if(r.nbyte < l) {
  113. c := 0;
  114. if(r.nbyte != 0) {
  115. b[0:] = r.buf[r.ptr:];
  116. l -= r.nbyte;
  117. c += r.nbyte;
  118. b = b[r.nbyte:];
  119. }
  120. bsize := len r.buf;
  121. while(l != 0) {
  122. r.nbyte = sys->read(r.fd, r.buf, bsize);
  123. if(r.nbyte <= 0) {
  124. r.nbyte = 0;
  125. return -1;
  126. }
  127. n := l;
  128. if(n > bsize)
  129. n = bsize;
  130. r.ptr = 0;
  131. b[0:] = r.buf[0:n];
  132. b = b[n:];
  133. r.nbyte -= n;
  134. r.ptr += n;
  135. l -= n;
  136. c += n;
  137. }
  138. return c;
  139. }
  140. b[0:] = r.buf[r.ptr:r.ptr+l];
  141. r.nbyte -= l;
  142. r.ptr += l;
  143. return l;
  144. }
  145. QD.skip(r: self ref QD, size: int): int
  146. {
  147. if(r.nbyte != 0) {
  148. n := size;
  149. if(n > r.nbyte)
  150. n = r.nbyte;
  151. r.ptr += n;
  152. r.nbyte -= n;
  153. size -= n;
  154. if(size == 0)
  155. return 0;
  156. }
  157. return int sys->seek(r.fd, big size, sys->SEEKRELA);
  158. }
  159. beword(b: array of byte, o: int): int
  160. {
  161. return (int b[o] << 8) | int b[o+1];
  162. }
  163. bedword(b: array of byte, o: int): int
  164. {
  165. return (int b[o] << 24) |
  166. (int b[o+1] << 16) |
  167. (int b[o+2] << 8) |
  168. int b[o+3];
  169. }