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.

332 lines
9.0KB

  1. /*
  2. * VMware Screen Codec (VMnc) decoder
  3. * Copyright (c) 2006 Konstantin Shishkov
  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. *
  19. */
  20. /**
  21. * @file vmnc.c
  22. * VMware Screen Codec (VMnc) decoder
  23. * As Alex Beregszaszi discovered, this is effectively RFB data dump
  24. */
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include "common.h"
  28. #include "avcodec.h"
  29. enum EncTypes {
  30. MAGIC_WMVd = 0x574D5664,
  31. MAGIC_WMVe,
  32. MAGIC_WMVf,
  33. MAGIC_WMVg,
  34. MAGIC_WMVh,
  35. MAGIC_WMVi,
  36. MAGIC_WMVj
  37. };
  38. enum HexTile_Flags {
  39. HT_RAW = 1, // tile is raw
  40. HT_BKG = 2, // background color is present
  41. HT_FG = 4, // foreground color is present
  42. HT_SUB = 8, // subrects are present
  43. HT_CLR = 16 // each subrect has own color
  44. };
  45. /*
  46. * Decoder context
  47. */
  48. typedef struct VmncContext {
  49. AVCodecContext *avctx;
  50. AVFrame pic;
  51. int bpp;
  52. int bpp2;
  53. int bigendian;
  54. uint8_t pal[768];
  55. int width, height;
  56. } VmncContext;
  57. /* read pixel value from stream */
  58. static always_inline int vmnc_get_pixel(uint8_t* buf, int bpp, int be) {
  59. switch(bpp * 2 + be) {
  60. case 2:
  61. case 3: return *buf;
  62. case 4: return LE_16(buf);
  63. case 5: return BE_16(buf);
  64. case 8: return LE_32(buf);
  65. case 9: return BE_32(buf);
  66. default: return 0;
  67. }
  68. }
  69. /* fill rectangle with given colour */
  70. static always_inline void paint_rect(uint8_t *dst, int dx, int dy, int w, int h, int color, int bpp, int stride)
  71. {
  72. int i, j;
  73. dst += dx * bpp + dy * stride;
  74. if(bpp == 1){
  75. for(j = 0; j < h; j++) {
  76. memset(dst, color, w);
  77. dst += stride;
  78. }
  79. }else if(bpp == 2){
  80. uint16_t* dst2;
  81. for(j = 0; j < h; j++) {
  82. dst2 = (uint16_t*)dst;
  83. for(i = 0; i < w; i++) {
  84. *dst2++ = color;
  85. }
  86. dst += stride;
  87. }
  88. }else if(bpp == 4){
  89. uint32_t* dst2;
  90. for(j = 0; j < h; j++) {
  91. dst2 = (uint32_t*)dst;
  92. for(i = 0; i < w; i++) {
  93. dst2[i] = color;
  94. }
  95. dst += stride;
  96. }
  97. }
  98. }
  99. static always_inline void paint_raw(uint8_t *dst, int w, int h, uint8_t* src, int bpp, int be, int stride)
  100. {
  101. int i, j, p;
  102. for(j = 0; j < h; j++) {
  103. for(i = 0; i < w; i++) {
  104. p = vmnc_get_pixel(src, bpp, be);
  105. src += bpp;
  106. switch(bpp){
  107. case 1:
  108. dst[i] = p;
  109. break;
  110. case 2:
  111. ((uint16_t*)dst)[i] = p;
  112. break;
  113. case 4:
  114. ((uint32_t*)dst)[i] = p;
  115. break;
  116. }
  117. }
  118. dst += stride;
  119. }
  120. }
  121. static int decode_hextile(VmncContext *c, uint8_t* dst, uint8_t* src, int w, int h, int stride)
  122. {
  123. int i, j, k;
  124. int bg = 0, fg = 0, rects, color, flags, xy, wh;
  125. const int bpp = c->bpp2;
  126. uint8_t *dst2;
  127. int bw = 16, bh = 16;
  128. uint8_t *ssrc=src;
  129. for(j = 0; j < h; j += 16) {
  130. dst2 = dst;
  131. bw = 16;
  132. if(j + 16 > h) bh = h - j;
  133. for(i = 0; i < w; i += 16, dst2 += 16 * bpp) {
  134. if(i + 16 > w) bw = w - i;
  135. flags = *src++;
  136. if(flags & HT_RAW) {
  137. paint_raw(dst2, bw, bh, src, bpp, c->bigendian, stride);
  138. src += bw * bh * bpp;
  139. } else {
  140. if(flags & HT_BKG) {
  141. bg = vmnc_get_pixel(src, bpp, c->bigendian); src += bpp;
  142. }
  143. if(flags & HT_FG) {
  144. fg = vmnc_get_pixel(src, bpp, c->bigendian); src += bpp;
  145. }
  146. rects = 0;
  147. if(flags & HT_SUB)
  148. rects = *src++;
  149. color = (flags & HT_CLR);
  150. paint_rect(dst2, 0, 0, bw, bh, bg, bpp, stride);
  151. for(k = 0; k < rects; k++) {
  152. if(color) {
  153. fg = vmnc_get_pixel(src, bpp, c->bigendian); src += bpp;
  154. }
  155. xy = *src++;
  156. wh = *src++;
  157. paint_rect(dst2, xy >> 4, xy & 0xF, (wh>>4)+1, (wh & 0xF)+1, fg, bpp, stride);
  158. }
  159. }
  160. }
  161. dst += stride * 16;
  162. }
  163. return src - ssrc;
  164. }
  165. static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size)
  166. {
  167. VmncContext * const c = (VmncContext *)avctx->priv_data;
  168. uint8_t *outptr;
  169. uint8_t *src = buf;
  170. int dx, dy, w, h, depth, enc, chunks, res;
  171. c->pic.reference = 1;
  172. c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
  173. if(avctx->reget_buffer(avctx, &c->pic) < 0){
  174. av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
  175. return -1;
  176. }
  177. c->pic.key_frame = 0;
  178. c->pic.pict_type = FF_P_TYPE;
  179. src += 2;
  180. chunks = BE_16(src); src += 2;
  181. while(chunks--) {
  182. dx = BE_16(src); src += 2;
  183. dy = BE_16(src); src += 2;
  184. w = BE_16(src); src += 2;
  185. h = BE_16(src); src += 2;
  186. enc = BE_32(src); src += 4;
  187. switch(enc) {
  188. case MAGIC_WMVd: // unknown
  189. src += 2;
  190. src += w * h * 8; // skip this data for now
  191. break;
  192. case MAGIC_WMVe: // unknown
  193. src += 2;
  194. break;
  195. case MAGIC_WMVf: // unknown and empty
  196. break;
  197. case MAGIC_WMVi: // ServerInitialization struct
  198. c->pic.key_frame = 1;
  199. c->pic.pict_type = FF_I_TYPE;
  200. depth = *src++;
  201. if(depth != c->bpp) {
  202. av_log(avctx, AV_LOG_INFO, "Depth mismatch. Container %i bpp, Frame data: %i bpp\n", c->bpp, depth);
  203. }
  204. src++;
  205. c->bigendian = *src++;
  206. if(c->bigendian & (~1)) {
  207. av_log(avctx, AV_LOG_INFO, "Invalid header: bigendian flag = %i\n", c->bigendian);
  208. return -1;
  209. }
  210. //skip the rest of pixel format data
  211. src += 13;
  212. break;
  213. case 0x00000000: // raw rectangle data
  214. if((dx + w > c->width) || (dy + h > c->height)) {
  215. av_log(avctx, AV_LOG_ERROR, "Incorrect frame size: %ix%i+%ix%i of %ix%i\n", w, h, dx, dy, c->width, c->height);
  216. return -1;
  217. }
  218. outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
  219. paint_raw(outptr, w, h, src, c->bpp2, c->bigendian, c->pic.linesize[0]);
  220. src += w * h * c->bpp2;
  221. break;
  222. case 0x00000005: // HexTile encoded rectangle
  223. if((dx + w > c->width) || (dy + h > c->height)) {
  224. av_log(avctx, AV_LOG_ERROR, "Incorrect frame size: %ix%i+%ix%i of %ix%i\n", w, h, dx, dy, c->width, c->height);
  225. return -1;
  226. }
  227. outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
  228. res = decode_hextile(c, outptr, src, w, h, c->pic.linesize[0]);
  229. if(res < 0)
  230. return -1;
  231. src += res;
  232. break;
  233. default:
  234. av_log(avctx, AV_LOG_ERROR, "Unsupported block type 0x%08X\n", enc);
  235. chunks = 0; // leave chunks decoding loop
  236. }
  237. }
  238. *data_size = sizeof(AVFrame);
  239. *(AVFrame*)data = c->pic;
  240. /* always report that the buffer was completely consumed */
  241. return buf_size;
  242. }
  243. /*
  244. *
  245. * Init VMnc decoder
  246. *
  247. */
  248. static int decode_init(AVCodecContext *avctx)
  249. {
  250. VmncContext * const c = (VmncContext *)avctx->priv_data;
  251. c->avctx = avctx;
  252. avctx->has_b_frames = 0;
  253. c->pic.data[0] = NULL;
  254. c->width = avctx->width;
  255. c->height = avctx->height;
  256. if (avcodec_check_dimensions(avctx, avctx->height, avctx->width) < 0) {
  257. return 1;
  258. }
  259. c->bpp = avctx->bits_per_sample;
  260. c->bpp2 = c->bpp/8;
  261. switch(c->bpp){
  262. case 8:
  263. avctx->pix_fmt = PIX_FMT_PAL8;
  264. break;
  265. case 16:
  266. avctx->pix_fmt = PIX_FMT_RGB555;
  267. break;
  268. case 32:
  269. avctx->pix_fmt = PIX_FMT_RGB32;
  270. break;
  271. default:
  272. av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", c->bpp);
  273. }
  274. return 0;
  275. }
  276. /*
  277. *
  278. * Uninit VMnc decoder
  279. *
  280. */
  281. static int decode_end(AVCodecContext *avctx)
  282. {
  283. VmncContext * const c = (VmncContext *)avctx->priv_data;
  284. if (c->pic.data[0])
  285. avctx->release_buffer(avctx, &c->pic);
  286. return 0;
  287. }
  288. AVCodec vmnc_decoder = {
  289. "VMware video",
  290. CODEC_TYPE_VIDEO,
  291. CODEC_ID_VMNC,
  292. sizeof(VmncContext),
  293. decode_init,
  294. NULL,
  295. decode_end,
  296. decode_frame
  297. };