screencodec.c 16 KB

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