You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

459 lines
11KB

  1. /*
  2. * SGI image format
  3. * Todd Kirby <doubleshot@pacbell.net>
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include "avformat.h"
  20. #include "avio.h"
  21. /* #define DEBUG */
  22. /* sgi image file signature */
  23. #define SGI_MAGIC 474
  24. #define SGI_HEADER_SIZE 512
  25. #define SGI_GRAYSCALE 1
  26. #define SGI_RGB 3
  27. #define SGI_RGBA 4
  28. #define SGI_SINGLE_CHAN 2
  29. #define SGI_MULTI_CHAN 3
  30. typedef struct SGIInfo{
  31. short magic;
  32. char rle;
  33. char bytes_per_channel;
  34. unsigned short dimension;
  35. unsigned short xsize;
  36. unsigned short ysize;
  37. unsigned short zsize;
  38. } SGIInfo;
  39. static int sgi_probe(AVProbeData *pd)
  40. {
  41. /* test for sgi magic */
  42. if (pd->buf_size >= 2 && BE_16(&pd->buf[0]) == SGI_MAGIC) {
  43. return AVPROBE_SCORE_MAX;
  44. } else {
  45. return 0;
  46. }
  47. }
  48. /* read sgi header fields */
  49. static void read_sgi_header(ByteIOContext *f, SGIInfo *info)
  50. {
  51. info->magic = (unsigned short) get_be16(f);
  52. info->rle = get_byte(f);
  53. info->bytes_per_channel = get_byte(f);
  54. info->dimension = (unsigned short)get_be16(f);
  55. info->xsize = (unsigned short) get_be16(f);
  56. info->ysize = (unsigned short) get_be16(f);
  57. info->zsize = (unsigned short) get_be16(f);
  58. if(info->zsize > 4096)
  59. info->zsize= 0;
  60. #ifdef DEBUG
  61. printf("sgi header fields:\n");
  62. printf(" magic: %d\n", info->magic);
  63. printf(" rle: %d\n", info->rle);
  64. printf(" bpc: %d\n", info->bytes_per_channel);
  65. printf(" dim: %d\n", info->dimension);
  66. printf(" xsize: %d\n", info->xsize);
  67. printf(" ysize: %d\n", info->ysize);
  68. printf(" zsize: %d\n", info->zsize);
  69. #endif
  70. return;
  71. }
  72. /* read an uncompressed sgi image */
  73. static int read_uncompressed_sgi(const SGIInfo *si,
  74. AVPicture *pict, ByteIOContext *f)
  75. {
  76. int x, y, z, chan_offset, ret = 0;
  77. uint8_t *dest_row;
  78. /* skip header */
  79. url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
  80. pict->linesize[0] = si->xsize;
  81. for (z = 0; z < si->zsize; z++) {
  82. #ifndef WORDS_BIGENDIAN
  83. /* rgba -> bgra for rgba32 on little endian cpus */
  84. if (si->zsize == 4 && z != 3)
  85. chan_offset = 2 - z;
  86. else
  87. #endif
  88. chan_offset = z;
  89. for (y = si->ysize - 1; y >= 0; y--) {
  90. dest_row = pict->data[0] + (y * si->xsize * si->zsize);
  91. for (x = 0; x < si->xsize; x++) {
  92. dest_row[chan_offset] = get_byte(f);
  93. dest_row += si->zsize;
  94. }
  95. }
  96. }
  97. return ret;
  98. }
  99. /* expand an rle row into a channel */
  100. static int expand_rle_row(ByteIOContext *f, unsigned char *optr,
  101. int chan_offset, int pixelstride)
  102. {
  103. unsigned char pixel, count;
  104. int length = 0;
  105. #ifndef WORDS_BIGENDIAN
  106. /* rgba -> bgra for rgba32 on little endian cpus */
  107. if (pixelstride == 4 && chan_offset != 3) {
  108. chan_offset = 2 - chan_offset;
  109. }
  110. #endif
  111. optr += chan_offset;
  112. while (1) {
  113. pixel = get_byte(f);
  114. if (!(count = (pixel & 0x7f))) {
  115. return length;
  116. }
  117. if (pixel & 0x80) {
  118. while (count--) {
  119. *optr = get_byte(f);
  120. length++;
  121. optr += pixelstride;
  122. }
  123. } else {
  124. pixel = get_byte(f);
  125. while (count--) {
  126. *optr = pixel;
  127. length++;
  128. optr += pixelstride;
  129. }
  130. }
  131. }
  132. }
  133. /* read a run length encoded sgi image */
  134. static int read_rle_sgi(const SGIInfo *sgi_info,
  135. AVPicture *pict, ByteIOContext *f)
  136. {
  137. uint8_t *dest_row;
  138. unsigned long *start_table;
  139. int y, z, xsize, ysize, zsize, tablen;
  140. long start_offset;
  141. int ret = 0;
  142. xsize = sgi_info->xsize;
  143. ysize = sgi_info->ysize;
  144. zsize = sgi_info->zsize;
  145. /* skip header */
  146. url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
  147. /* size of rle offset and length tables */
  148. tablen = ysize * zsize * sizeof(long);
  149. start_table = (unsigned long *)av_malloc(tablen);
  150. if (!get_buffer(f, (uint8_t *)start_table, tablen)) {
  151. ret = AVERROR_IO;
  152. goto fail;
  153. }
  154. /* skip run length table */
  155. url_fseek(f, tablen, SEEK_CUR);
  156. for (z = 0; z < zsize; z++) {
  157. for (y = 0; y < ysize; y++) {
  158. dest_row = pict->data[0] + (ysize - 1 - y) * (xsize * zsize);
  159. start_offset = BE_32(&start_table[y + z * ysize]);
  160. /* don't seek if already at the next rle start offset */
  161. if (url_ftell(f) != start_offset) {
  162. url_fseek(f, start_offset, SEEK_SET);
  163. }
  164. if (expand_rle_row(f, dest_row, z, zsize) != xsize) {
  165. ret = AVERROR_INVALIDDATA;
  166. goto fail;
  167. }
  168. }
  169. }
  170. fail:
  171. av_free(start_table);
  172. return ret;
  173. }
  174. static int sgi_read(ByteIOContext *f,
  175. int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
  176. {
  177. SGIInfo sgi_info, *s = &sgi_info;
  178. AVImageInfo info1, *info = &info1;
  179. int ret;
  180. read_sgi_header(f, s);
  181. if (s->bytes_per_channel != 1) {
  182. return AVERROR_INVALIDDATA;
  183. }
  184. /* check for supported image dimensions */
  185. if (s->dimension != 2 && s->dimension != 3) {
  186. return AVERROR_INVALIDDATA;
  187. }
  188. if (s->zsize == SGI_GRAYSCALE) {
  189. info->pix_fmt = PIX_FMT_GRAY8;
  190. } else if (s->zsize == SGI_RGB) {
  191. info->pix_fmt = PIX_FMT_RGB24;
  192. } else if (s->zsize == SGI_RGBA) {
  193. info->pix_fmt = PIX_FMT_RGBA32;
  194. } else {
  195. return AVERROR_INVALIDDATA;
  196. }
  197. info->width = s->xsize;
  198. info->height = s->ysize;
  199. ret = alloc_cb(opaque, info);
  200. if (ret)
  201. return ret;
  202. if (s->rle) {
  203. return read_rle_sgi(s, &info->pict, f);
  204. } else {
  205. return read_uncompressed_sgi(s, &info->pict, f);
  206. }
  207. return 0; /* not reached */
  208. }
  209. #ifdef CONFIG_ENCODERS
  210. static void write_sgi_header(ByteIOContext *f, const SGIInfo *info)
  211. {
  212. int i;
  213. put_be16(f, SGI_MAGIC);
  214. put_byte(f, info->rle);
  215. put_byte(f, info->bytes_per_channel);
  216. put_be16(f, info->dimension);
  217. put_be16(f, info->xsize);
  218. put_be16(f, info->ysize);
  219. put_be16(f, info->zsize);
  220. /* The rest are constant in this implementation */
  221. put_be32(f, 0L); /* pixmin */
  222. put_be32(f, 255L); /* pixmax */
  223. put_be32(f, 0L); /* dummy */
  224. /* name */
  225. for (i = 0; i < 80; i++) {
  226. put_byte(f, 0);
  227. }
  228. put_be32(f, 0L); /* colormap */
  229. /* The rest of the 512 byte header is unused. */
  230. for (i = 0; i < 404; i++) {
  231. put_byte(f, 0);
  232. }
  233. }
  234. static int rle_row(ByteIOContext *f, char *row, int stride, int rowsize)
  235. {
  236. int length, count, i, x;
  237. char *start, repeat = 0;
  238. for (x = rowsize, length = 0; x > 0;) {
  239. start = row;
  240. row += (2 * stride);
  241. x -= 2;
  242. while (x > 0 && (row[-2 * stride] != row[-1 * stride] ||
  243. row[-1 * stride] != row[0])) {
  244. row += stride;
  245. x--;
  246. };
  247. row -= (2 * stride);
  248. x += 2;
  249. count = (row - start) / stride;
  250. while (count > 0) {
  251. i = count > 126 ? 126 : count;
  252. count -= i;
  253. put_byte(f, 0x80 | i);
  254. length++;
  255. while (i > 0) {
  256. put_byte(f, *start);
  257. start += stride;
  258. i--;
  259. length++;
  260. };
  261. };
  262. if (x <= 0) {
  263. break;
  264. }
  265. start = row;
  266. repeat = row[0];
  267. row += stride;
  268. x--;
  269. while (x > 0 && *row == repeat) {
  270. row += stride;
  271. x--;
  272. };
  273. count = (row - start) / stride;
  274. while (count > 0) {
  275. i = count > 126 ? 126 : count;
  276. count -= i;
  277. put_byte(f, i);
  278. length++;
  279. put_byte(f, repeat);
  280. length++;
  281. };
  282. };
  283. length++;
  284. put_byte(f, 0);
  285. return (length);
  286. }
  287. static int sgi_write(ByteIOContext *pb, AVImageInfo *info)
  288. {
  289. SGIInfo sgi_info, *si = &sgi_info;
  290. long *offsettab, *lengthtab;
  291. int i, y, z;
  292. int tablesize, chan_offset;
  293. uint8_t *srcrow;
  294. si->xsize = info->width;
  295. si->ysize = info->height;
  296. si->rle = 1;
  297. si->bytes_per_channel = 1;
  298. switch(info->pix_fmt) {
  299. case PIX_FMT_GRAY8:
  300. si->dimension = SGI_SINGLE_CHAN;
  301. si->zsize = SGI_GRAYSCALE;
  302. break;
  303. case PIX_FMT_RGB24:
  304. si->dimension = SGI_MULTI_CHAN;
  305. si->zsize = SGI_RGB;
  306. break;
  307. case PIX_FMT_RGBA32:
  308. si->dimension = SGI_MULTI_CHAN;
  309. si->zsize = SGI_RGBA;
  310. break;
  311. default:
  312. return AVERROR_INVALIDDATA;
  313. }
  314. write_sgi_header(pb, si);
  315. tablesize = si->zsize * si->ysize * sizeof(long);
  316. /* skip rle offset and length tables, write them at the end. */
  317. url_fseek(pb, tablesize * 2, SEEK_CUR);
  318. put_flush_packet(pb);
  319. lengthtab = av_malloc(tablesize);
  320. offsettab = av_malloc(tablesize);
  321. for (z = 0; z < si->zsize; z++) {
  322. #ifndef WORDS_BIGENDIAN
  323. /* rgba -> bgra for rgba32 on little endian cpus */
  324. if (si->zsize == 4 && z != 3)
  325. chan_offset = 2 - z;
  326. else
  327. #endif
  328. chan_offset = z;
  329. srcrow = info->pict.data[0] + chan_offset;
  330. for (y = si->ysize -1; y >= 0; y--) {
  331. offsettab[(z * si->ysize) + y] = url_ftell(pb);
  332. lengthtab[(z * si->ysize) + y] = rle_row(pb, srcrow,
  333. si->zsize, si->xsize);
  334. srcrow += info->pict.linesize[0];
  335. }
  336. }
  337. url_fseek(pb, 512, SEEK_SET);
  338. /* write offset table */
  339. for (i = 0; i < (si->ysize * si->zsize); i++) {
  340. put_be32(pb, offsettab[i]);
  341. }
  342. /* write length table */
  343. for (i = 0; i < (si->ysize * si->zsize); i++) {
  344. put_be32(pb, lengthtab[i]);
  345. }
  346. put_flush_packet(pb);
  347. av_free(lengthtab);
  348. av_free(offsettab);
  349. return 0;
  350. }
  351. #endif // CONFIG_ENCODERS
  352. AVImageFormat sgi_image_format = {
  353. "sgi",
  354. "sgi,rgb,rgba,bw",
  355. sgi_probe,
  356. sgi_read,
  357. (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_RGBA32),
  358. #ifdef CONFIG_ENCODERS
  359. sgi_write,
  360. #else
  361. NULL,
  362. #endif // CONFIG_ENCODERS
  363. };