screencodec.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. #include "screencodec.h"
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #ifdef _WIN32
  5. #include <WinSock.h>
  6. #include <ipp.h>
  7. #else
  8. #include "SpBase.h"
  9. #endif
  10. #include <assert.h>
  11. #include <zlib.h>
  12. #define ZALLOC(size) zalloc(size)
  13. #define ZCALLOC(num, size) czalloc(num, size)
  14. #define MALLOC_T(type) (type*)malloc(sizeof(type))
  15. #define ZALLOC_T(type) (type*)zalloc(sizeof(type))
  16. #define CALLOC_T(num, type) (type*)calloc(num, sizeof(type))
  17. #ifndef BS_WRITE_I2
  18. #define BS_WRITE_I2(ptr, v) \
  19. do{\
  20. *(unsigned char*)ptr = v&0x00ff; \
  21. *((unsigned char*)ptr+1) = (v&0xff00) >> 8;\
  22. }while(0)\
  23. #endif // !BS_WRITE_I2
  24. static __inline int output(unsigned short *buf, int *size, unsigned int color, unsigned int count)
  25. {
  26. int n = *size;
  27. assert(count);
  28. if (count == 1) {
  29. buf[n++] = color;
  30. } else if (count <= 0x7fff) {
  31. buf[n++] = color | 0x8000;
  32. buf[n++] = count | 0x8000;
  33. } else {
  34. buf[n++] = color | 0x8000;
  35. buf[n++] = count & 0x7fff;
  36. buf[n++] = 0x8000 | ((count & 0x3fff8000) >> 15);
  37. }
  38. *size = n;
  39. return 0;
  40. }
  41. static void rle_encode(int width, int height, const unsigned char *raw_buf, unsigned short *buf, int *size)
  42. {
  43. const unsigned char *p = raw_buf;
  44. unsigned int last = -1, count = 0;
  45. int linesize = (width * 3 + 3) & 0xfffffffc;
  46. int len = 0;
  47. int i;
  48. for (i = 0; i < height; ++i) {
  49. const unsigned char *s = p;
  50. const unsigned char *e = p + width*3;
  51. while (p != e) {
  52. unsigned int b = *p++;
  53. unsigned int g = *p++;
  54. unsigned int r = *p++;
  55. unsigned int curr = ((r & 0xf8) << 7) | ((g&0xf8) << 2) | ((b & 0xf8) >> 3); // rgb555
  56. if (last != curr) {
  57. if (count) {
  58. output(buf, &len, last, count);
  59. }
  60. last = curr;
  61. count = 1;
  62. } else {
  63. count++;
  64. }
  65. }
  66. p = s + linesize;
  67. }
  68. output(buf, &len, last, count);
  69. *size = len;
  70. }
  71. SCREENCODEC_API(int) screencapture_encode(int width, int height, const void *raw_buf, void *buf, int *size)
  72. {
  73. unsigned char *p;
  74. unsigned short *tmp_buf;
  75. int tmp_len;
  76. int rc;
  77. unsigned long src_len, dst_len;
  78. if (!buf) {
  79. if (size) {
  80. *size = width * height *3; // at most
  81. return 0;
  82. }
  83. return -1;
  84. }
  85. if (!raw_buf || !buf)
  86. return -1;
  87. p = buf;
  88. BS_WRITE_I2(p, width);
  89. p += 2;
  90. BS_WRITE_I2(p, height);
  91. p += 2;
  92. tmp_len = width * height * 3;
  93. tmp_buf = (unsigned short*)malloc(tmp_len<<1);
  94. rle_encode(width, height, raw_buf, tmp_buf, &tmp_len);
  95. dst_len = *size - (p-(unsigned char*)buf);
  96. src_len = tmp_len << 1;
  97. rc = compress(p, &dst_len, (Bytef*)tmp_buf, src_len);
  98. free(tmp_buf);
  99. if (rc == 0) {
  100. p += dst_len;
  101. *size = p - (unsigned char *)buf;
  102. }
  103. return rc;
  104. }
  105. static int input(unsigned short **pp, unsigned short *end, unsigned int *color, unsigned int *count)
  106. {
  107. unsigned short *p = *pp;
  108. if (p != end) {
  109. unsigned short t = *p++;
  110. if (t & 0x8000) {
  111. if (p != end) {
  112. unsigned short tt = *p++;
  113. if (tt & 0x8000) {
  114. *count = tt & 0x7fff;
  115. *color = t & 0x7fff;
  116. } else {
  117. if (p != end) {
  118. unsigned short ttt = *p++;
  119. if (ttt & 0x8000) {
  120. *color = t & 0x7fff;
  121. *count = (((unsigned int)ttt & 0x7fff) << 15) | ((unsigned int)tt & 0x7fff);
  122. } else {
  123. return -1;
  124. }
  125. } else {
  126. return -1;
  127. }
  128. }
  129. } else {
  130. return -1;
  131. }
  132. } else {
  133. *color = t;
  134. *count = 1;
  135. }
  136. } else {
  137. return -1;
  138. }
  139. *pp = p;
  140. return 0;
  141. }
  142. static int rle_decode(const void *src_buf, int size, int width, int height, unsigned char *buf)
  143. {
  144. int rc = 0;
  145. int i = 0, j = 0;
  146. int linesize = (width * 3 + 3) & 0xfffffffc;
  147. int linegap = linesize - width * 3;
  148. unsigned char *c = (unsigned char*)buf;
  149. unsigned short *p = (unsigned short*)src_buf;
  150. unsigned short *e = (unsigned short*)((const char*)src_buf + size);
  151. while (p != e) {
  152. unsigned int color, count;
  153. int r, g, b;
  154. rc = input(&p, e, &color, &count);
  155. if (rc != 0)
  156. break;
  157. b = (color & 0x1f) << 3;
  158. g = (color & 0x3e0) >> 2;
  159. r = (color & 0x7c00) >> 7;
  160. while (i < height && count > 0) {
  161. while (j < width && count > 0) {
  162. *c++ = b;
  163. *c++ = g;
  164. *c++ = r;
  165. j ++;
  166. count --;
  167. }
  168. if (j == width) {
  169. j = 0;
  170. i++;
  171. c += linegap;
  172. }
  173. }
  174. }
  175. return rc;
  176. }
  177. SCREENCODEC_API(int) screencapture_decode(int *width, int *height, const void *enc_buf, size_t enc_size, void *buf, int *size)
  178. {
  179. const unsigned short *i2 = (const unsigned short *)enc_buf;
  180. int linesize;
  181. int linegap;
  182. unsigned char *tmp_buf;
  183. unsigned long tmp_len;
  184. int rc;
  185. *width = i2[0];
  186. *height = i2[1];
  187. linesize = (*width * 3 + 3) & 0xfffffffc;
  188. linegap = linesize - *width * 3;
  189. if (!buf) {
  190. *size = linesize * *height;
  191. return 0;
  192. }
  193. tmp_len = *width * *height * 3;
  194. tmp_buf = (unsigned char*)malloc(tmp_len);
  195. rc = uncompress(tmp_buf, &tmp_len, (Bytef*)&i2[2], enc_size-4);
  196. if (rc == 0) {
  197. rc = rle_decode(tmp_buf, tmp_len, *width, *height, buf);
  198. }
  199. free(tmp_buf);
  200. return rc;
  201. }
  202. #define SCREEN_CODEC_VER 1
  203. #define SCREEN_CODEC_TAG 'RVC '
  204. #define SCREEN_CODEC_TYPE_I 0
  205. #define SCREEN_CODEC_TYPE_P 1
  206. typedef struct screen_codec_hdr_t
  207. {
  208. unsigned int tag;
  209. unsigned int version : 3;
  210. unsigned int frame_type : 2;
  211. unsigned int compress : 1;
  212. unsigned int frame_id : 26;
  213. unsigned short width;
  214. unsigned short height;
  215. unsigned int size;
  216. }screen_codec_hdr_t;
  217. // 0: rle
  218. // 1-254: spr
  219. // 255: ref
  220. struct screen_encoder_session_t
  221. {
  222. BYTE *ref_frame;
  223. int width;
  224. int height;
  225. int seq_no;
  226. };
  227. static void img_rgb24_to_rgb8(int width, int height, const unsigned char *src, unsigned char *dst)
  228. {
  229. const unsigned char *s = src;
  230. const unsigned char *e = s + width * height * 3;
  231. while (s != e) {
  232. *dst++ = ((s[0] & 0xC0) >> 6) | ((s[1] & 0xF0) >> 2) | (s[2] & 0xC0);
  233. s += 3;
  234. }
  235. }
  236. static void img_rgb8_to_rgb24(int width, int height, const unsigned char *src, unsigned char *dst)
  237. {
  238. const unsigned char *s = src;
  239. const unsigned char *e = s + width * height;
  240. while (s != e) {
  241. unsigned int ch = *s;
  242. *dst++ = (ch & 3) << 6;
  243. *dst++ = (ch & 0x3c) << 2;
  244. *dst++ = (ch & 0xc0);
  245. s++;
  246. }
  247. }
  248. static int scan_rle_chunk(const unsigned char *s, const unsigned char *e)
  249. {
  250. if (s == e) {
  251. return 0;
  252. } else {
  253. const unsigned char *ss = s;
  254. int ch = *ss;
  255. ss++;
  256. while (ss < e) {
  257. if (ch == *ss)
  258. ss++;
  259. else
  260. break;
  261. }
  262. return ss - s;
  263. }
  264. }
  265. static int scan_ref_chunk(const unsigned char *s, const unsigned char *e, const unsigned char *s_ref)
  266. {
  267. if (s == e) {
  268. return 0;
  269. } else {
  270. const unsigned char *ss = s;
  271. const unsigned char *ss_ref = s_ref;
  272. while (ss < e) {
  273. if (*ss == *ss_ref) {
  274. ss++;
  275. ss_ref++;
  276. } else {
  277. break;
  278. }
  279. }
  280. return ss - s;
  281. }
  282. }
  283. typedef struct enc_output_ctx {
  284. int n;
  285. char spr[256];
  286. }enc_output_ctx;
  287. static int output_spr(enc_output_ctx *ctx, unsigned char *output)
  288. {
  289. unsigned char *o = output;
  290. *o++ = (unsigned char)ctx->n;
  291. memcpy(o, ctx->spr, ctx->n);
  292. o += ctx->n;
  293. ctx->n = 0;
  294. return o - output;
  295. }
  296. static __inline int output_rle_chunk(enc_output_ctx *ctx, const unsigned char *chunk, int chunk_len, unsigned char *output)
  297. {
  298. unsigned char *o = output;
  299. if (chunk_len == 1) {
  300. ctx->spr[ctx->n++] = *chunk;
  301. if (ctx->n == 254) {
  302. o += output_spr(ctx, o);
  303. return o - output;
  304. }
  305. return 0;
  306. } else {
  307. if (ctx->n > 0) {
  308. o += output_spr(ctx, o);
  309. }
  310. *o++ = 0; // rle start
  311. while (chunk_len >= 0x80) {
  312. *o++ = (unsigned char)(chunk_len | 0x80);
  313. chunk_len >>= 7;
  314. }
  315. *o++ = (unsigned char)chunk_len;
  316. *o++ = *chunk;
  317. return o - output;
  318. }
  319. }
  320. static __inline int output_ref_chunk(enc_output_ctx *ctx, int chunk_len, unsigned char *output)
  321. {
  322. unsigned char *o = output;
  323. if (ctx->n > 0) {
  324. o += output_spr(ctx, o);
  325. }
  326. *o++ = 0xff; // ref start
  327. while (chunk_len >= 0x80) {
  328. *o++ = (unsigned char)(chunk_len | 0x80);
  329. chunk_len >>= 7;
  330. }
  331. *o++ = (unsigned char)chunk_len;
  332. return o - output;
  333. }
  334. static int encode(screen_encoder_session_t *session, const unsigned char* o, unsigned char *output)
  335. {
  336. const unsigned char *s = o;
  337. const unsigned char *e = s + session->width * session->height;
  338. unsigned char *oo = output;
  339. enc_output_ctx ctx;
  340. int r0, r1;
  341. ctx.n = 0;
  342. for (;;) {
  343. if (session ->ref_frame) {
  344. r0 = scan_ref_chunk(s, e, session->ref_frame + (s - o));
  345. } else {
  346. r0 = 0;
  347. }
  348. r1 = scan_rle_chunk(s, e);
  349. if (r0 > r1) {
  350. if (r0 < 5) {
  351. oo += output_rle_chunk(&ctx, s, r1, oo);
  352. s += r1;
  353. } else {
  354. oo += output_ref_chunk(&ctx, r0, oo);
  355. s += r0;
  356. }
  357. } else if (r0 < r1) {
  358. oo += output_rle_chunk(&ctx, s, r1, oo);
  359. s += r1;
  360. } else {
  361. if (r1 == 0) {
  362. break; // finished
  363. }
  364. oo += output_rle_chunk(&ctx, s, r1, oo);
  365. s += r1;
  366. }
  367. }
  368. if (ctx.n > 0) {
  369. oo += output_spr(&ctx, oo);
  370. }
  371. return oo - output;
  372. }
  373. static int encode_frame(screen_encoder_session_t *session, const unsigned char* raw, unsigned char *output, int *size, int *type)
  374. {
  375. unsigned char *rgb8_buf = (unsigned char*)malloc(session->width * session->height);
  376. img_rgb24_to_rgb8(session->width, session->height, raw, rgb8_buf);
  377. *size = encode(session, rgb8_buf, output);
  378. if (!session->ref_frame) {
  379. session->ref_frame = (BYTE*)malloc(session->width * session->height);
  380. memcpy(session->ref_frame, rgb8_buf, session->width * session->height);
  381. *type = SCREEN_CODEC_TYPE_I;
  382. } else {
  383. memcpy(session->ref_frame, rgb8_buf, session->width * session->height);
  384. *type = SCREEN_CODEC_TYPE_P;
  385. }
  386. free(rgb8_buf);
  387. return 0;
  388. }
  389. SCREENCODEC_API(int) screen_encoder_session_create(int width, int height, screen_encoder_session_t **p_session)
  390. {
  391. #ifdef _WIN32
  392. screen_encoder_session_t *session = MALLOC_T(screen_encoder_session_t);
  393. #else
  394. screen_encoder_session_t *session = malloc(sizeof(screen_encoder_session_t));
  395. #endif
  396. if (session) {
  397. session->width = width;
  398. session->height = height;
  399. session->ref_frame = NULL;
  400. session->seq_no = 0;
  401. *p_session = session;
  402. return 0;
  403. }
  404. return -1;
  405. }
  406. SCREENCODEC_API(void) screen_encoder_session_destroy(screen_encoder_session_t *session)
  407. {
  408. if (session) {
  409. if (session->ref_frame) {
  410. free(session->ref_frame);
  411. session->ref_frame = NULL;
  412. }
  413. free(session);
  414. }
  415. }
  416. #pragma optimize("", off)
  417. SCREENCODEC_API(int) screen_encoder_session_encode(screen_encoder_session_t *session, const void *raw, void *buf, int *size)
  418. {
  419. int rc;
  420. if (!session)
  421. return -1;
  422. if (!raw)
  423. return -1;
  424. if (!buf) {
  425. if (size) {
  426. *size = session->width * session->height * 3 + sizeof(screen_codec_hdr_t); // at most
  427. return 0;
  428. }
  429. return -1;
  430. }
  431. if (!size)
  432. return -1;
  433. rc = 0;
  434. {
  435. int len = 0;
  436. int type = 0;
  437. void *tmp_buf = malloc(session->width * session->height * 3 * 2);
  438. rc = encode_frame(session, raw, (unsigned char*)tmp_buf, &len, &type);
  439. if (rc == 0) {
  440. unsigned long dst_len;
  441. rc = compress((char*)buf+sizeof(screen_codec_hdr_t), &dst_len, tmp_buf, len);
  442. if (rc == 0) {
  443. if (dst_len < len) { // compress
  444. screen_codec_hdr_t *hdr = (screen_codec_hdr_t *)buf;
  445. hdr->tag = SCREEN_CODEC_TAG;
  446. hdr->version = SCREEN_CODEC_VER;
  447. hdr->frame_type = type;
  448. hdr->compress = 1;
  449. hdr->frame_id = session->seq_no++;
  450. hdr->width = session->width;
  451. hdr->height = session->height;
  452. hdr->size = dst_len;
  453. *size = hdr->size + sizeof(screen_codec_hdr_t);
  454. } else {
  455. screen_codec_hdr_t *hdr = (screen_codec_hdr_t *)buf;
  456. hdr->tag = SCREEN_CODEC_TAG;
  457. hdr->version = SCREEN_CODEC_VER;
  458. hdr->frame_type = type;
  459. hdr->compress = 0;
  460. hdr->frame_id = session->seq_no++;
  461. hdr->width = session->width;
  462. hdr->height = session->height;
  463. hdr->size = len;
  464. *size = hdr->size + sizeof(screen_codec_hdr_t);
  465. memcpy((char*)buf+sizeof(screen_codec_hdr_t), tmp_buf, len);
  466. }
  467. }
  468. }
  469. free(tmp_buf);
  470. }
  471. return rc;
  472. }
  473. #pragma optimize("", on)
  474. struct screen_decoder_session_t
  475. {
  476. BYTE *ref_frame;
  477. int width;
  478. int height;
  479. int seq_no;
  480. };
  481. static __inline int expand_spr_chunk(int spr_len, const unsigned char *spr, unsigned char *s, unsigned char *e)
  482. {
  483. if (e-s >= spr_len) {
  484. memcpy(s, spr, spr_len);
  485. return spr_len;
  486. } else {
  487. return -1;
  488. }
  489. }
  490. static __inline int expand_rle_chunk(int u, int u_len, unsigned char *s, unsigned char *e)
  491. {
  492. if ((e - s) >= u_len) {
  493. memset(s, u, u_len);
  494. return u_len;
  495. } else {
  496. return -1;
  497. }
  498. }
  499. static __inline int expand_ref_chunk(int len, unsigned char *s, unsigned char *e, unsigned char *s_ref)
  500. {
  501. if ((e - s) >= len) {
  502. memcpy(s, s_ref, len);
  503. return len;
  504. } else {
  505. return -1;
  506. }
  507. }
  508. static int read_7bit_int(const unsigned char *__s, const unsigned char *e, int *cnt)
  509. {
  510. int count = 0;
  511. int shift = 0;
  512. const unsigned char *s = __s;
  513. unsigned char b;
  514. if (s == e)
  515. return -1;
  516. do {
  517. if (shift == 5*7)
  518. return -1; // currupt
  519. b = *s++;
  520. count |= (b & 0x7f) << shift;
  521. shift += 7;
  522. } while(b >= 0x80 && s < e);
  523. *cnt = count;
  524. return s - __s;
  525. }
  526. static int read_chunk(screen_decoder_session_t *session, const unsigned char *__ss, const unsigned char *ee, int *prefix, int *count, int *color)
  527. {
  528. if (__ss == ee) {
  529. return 0;
  530. } else {
  531. const unsigned char *ss = __ss;
  532. *prefix = *ss++;
  533. if (ss == ee)
  534. return -1;
  535. if (*prefix == 0) { // rle
  536. int n;
  537. int rc = read_7bit_int(ss, ee, &n);
  538. if (rc < 0)
  539. return -1; // error
  540. ss += rc;
  541. *count = n;
  542. *color = *ss++;
  543. return ss - __ss;
  544. } else if (*prefix == 0xff) { // ref
  545. int n;
  546. int rc = read_7bit_int(ss, ee, &n);
  547. if (rc < 0)
  548. return -1; // error
  549. ss += rc;
  550. *count = n;
  551. return ss - __ss;
  552. } else {
  553. *count = *prefix;
  554. return ss - __ss;
  555. }
  556. }
  557. }
  558. static int decode(screen_decoder_session_t *session, const void *enc_buf, size_t enc_size, unsigned char *output)
  559. {
  560. unsigned char *s = (unsigned char*)output;
  561. unsigned char *e = s + session->width * session->height;
  562. const unsigned char *ss = (unsigned char *)enc_buf;
  563. const unsigned char *ee = (unsigned char *)enc_buf + enc_size;
  564. int rc;
  565. int prefix;
  566. int color;
  567. int count;
  568. for (;;) {
  569. rc = read_chunk(session, ss, ee, &prefix, &count, &color);
  570. if (rc > 0) {
  571. if (prefix == 0) { // rle
  572. int t = expand_rle_chunk(color, count, s, e);
  573. if (t < 0)
  574. return -1;
  575. s += t;
  576. ss += rc;
  577. } else if (prefix == 0xff) { // ref
  578. int t;
  579. if (!session->ref_frame)
  580. return -1;
  581. t = expand_ref_chunk(count, s, e, session->ref_frame + (s - output));
  582. if (t < 0)
  583. return -1;
  584. s += t;
  585. ss += rc;
  586. } else {
  587. int t;
  588. ss += rc;
  589. t = expand_spr_chunk(count, ss, s, e);
  590. if (t < 0)
  591. return -1;
  592. ss += t;
  593. s += t;
  594. }
  595. } else if (rc == 0) {
  596. break; // finished
  597. } else {
  598. return -1; // error
  599. }
  600. }
  601. return ss == ee ? 0 : -1;
  602. }
  603. static int decode_frame(screen_decoder_session_t *session, const void *enc_buf, size_t enc_size, void *output)
  604. {
  605. void *rgb8_buf = malloc(session->width * session->height);
  606. int rc = decode(session, enc_buf, enc_size, rgb8_buf);
  607. if (rc == 0) {
  608. img_rgb8_to_rgb24(session->width, session->height, (unsigned char*)rgb8_buf, (unsigned char*)output);
  609. if (!session->ref_frame)
  610. session->ref_frame = (BYTE*)malloc(session->width * session->height);
  611. memcpy(session->ref_frame, rgb8_buf, session->width * session->height);
  612. }
  613. free(rgb8_buf);
  614. return rc;
  615. }
  616. SCREENCODEC_API(int) screen_decoder_session_create(screen_decoder_session_t **p_session)
  617. {
  618. #ifdef _WIN32
  619. screen_decoder_session_t *session = MALLOC_T(screen_decoder_session_t);
  620. #else
  621. screen_decoder_session_t *session = malloc(sizeof(screen_decoder_session_t));
  622. #endif //_WIN32
  623. if (session) {
  624. session->width = 0;
  625. session->height = 0;
  626. session->ref_frame = NULL;
  627. session->seq_no = 0;
  628. *p_session = session;
  629. return 0;
  630. }
  631. return -1;
  632. }
  633. SCREENCODEC_API(void) screen_decoder_session_destroy(screen_decoder_session_t *session)
  634. {
  635. if (session) {
  636. if (session->ref_frame) {
  637. free(session->ref_frame);
  638. session->ref_frame = NULL;
  639. }
  640. free(session);
  641. }
  642. }
  643. SCREENCODEC_API(int) screen_decoder_session_decode(screen_decoder_session_t *session, const void *enc_buf, size_t enc_size, int *width, int *height, void *buf, int *size)
  644. {
  645. int rc;
  646. const screen_codec_hdr_t *hdr;
  647. if (!session)
  648. return -1;
  649. if (!enc_buf)
  650. return -1;
  651. if (enc_size <= sizeof(screen_codec_hdr_t))
  652. return -1;
  653. hdr = (const screen_codec_hdr_t*)enc_buf;
  654. if (hdr->tag != SCREEN_CODEC_TAG)
  655. return -1;
  656. if (hdr->version != SCREEN_CODEC_VER)
  657. return -1;
  658. if (session->ref_frame) {
  659. if (hdr->frame_id != session->seq_no+1)
  660. return -1;
  661. if (hdr->width != session->width)
  662. return -1;
  663. if (hdr->height != session->height)
  664. return -1;
  665. } else {
  666. session->width = hdr->width;
  667. session->height = hdr->height;
  668. }
  669. if (!buf) {
  670. if (width) {
  671. *width = hdr->width;
  672. }
  673. if (height) {
  674. *height = hdr->height;
  675. }
  676. if (size) {
  677. *size = hdr->width * hdr->height * 3;
  678. return 0;
  679. }
  680. return -1;
  681. }
  682. if (hdr->compress == 0) {
  683. rc = decode_frame(session, (const void *)(hdr+1), hdr->size, buf);
  684. } else {
  685. unsigned long dst_len = session->width * session->height * 3;
  686. void *tmp_buf = malloc(dst_len);
  687. rc = uncompress(tmp_buf, &dst_len, (const void*)(hdr+1), hdr->size);
  688. if (rc == 0) {
  689. rc = decode_frame(session, tmp_buf, dst_len, buf);
  690. }
  691. free(tmp_buf);
  692. }
  693. if (rc == 0) {
  694. session->seq_no = hdr->frame_id;
  695. }
  696. return rc;
  697. }