plink_server.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. * Copyright (c) 2021 Alibaba Group. All rights reserved.
  3. * License-Identifier: Apache-2.0
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License"); you may
  6. * not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <fcntl.h>
  22. #include <sys/mman.h>
  23. #include <pthread.h>
  24. #include <memory.h>
  25. #include <errno.h>
  26. #include "process_linker_types.h"
  27. #include "video_mem.h"
  28. #ifndef NULL
  29. #define NULL ((void *)0)
  30. #endif
  31. #define NUM_OF_BUFFERS 5
  32. #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
  33. } while (0)
  34. typedef struct _ServerParams
  35. {
  36. char *plinkname;
  37. char *inputfile;
  38. PlinkColorFormat format;
  39. int width;
  40. int height;
  41. int stride;
  42. int frames;
  43. } ServerParams;
  44. typedef struct _PlinkChannel
  45. {
  46. PlinkChannelID id;
  47. PlinkHandle plink;
  48. PlinkPacket pkt;
  49. int sendid;
  50. int backid;
  51. int exit;
  52. int available_bufs;
  53. } PlinkChannel;
  54. typedef struct _PictureBuffer
  55. {
  56. unsigned int bus_address;
  57. void *virtual_address;
  58. unsigned int size;
  59. int fd;
  60. } PictureBuffer;
  61. void printUsage(char *name)
  62. {
  63. printf("usage: %s [options]\n"
  64. "\n"
  65. " Available options:\n"
  66. " -l plink file name (default: /tmp/plink.test)\n"
  67. " -i input YUV file name (mandatory)\n"
  68. " -f input color format (default: 3)\n"
  69. " 2 - I420\n"
  70. " 3 - NV12\n"
  71. " 4 - P010\n"
  72. " 14 - Bayer Raw 10bit\n"
  73. " 15 - Bayer Raw 12bit\n"
  74. " -w video width (mandatory)\n"
  75. " -h video height (mandatory)\n"
  76. " -s video buffer stride in bytes (default: video width)\n"
  77. " -n number of frames to send (default: 10)\n"
  78. "\n", name);
  79. }
  80. void parseParams(int argc, char **argv, ServerParams *params)
  81. {
  82. int i = 1;
  83. memset(params, 0, sizeof(*params));
  84. params->plinkname = "/tmp/plink.test";
  85. params->format = PLINK_COLOR_FormatYUV420SemiPlanar;
  86. params->frames = 10;
  87. while (i < argc)
  88. {
  89. if (argv[i][0] != '-' || strlen(argv[i]) < 2)
  90. {
  91. i++;
  92. continue;
  93. }
  94. if (argv[i][1] == 'l')
  95. {
  96. if (++i < argc)
  97. {
  98. params->plinkname = argv[i++];
  99. }
  100. }
  101. else if (argv[i][1] == 'i')
  102. {
  103. if (++i < argc)
  104. {
  105. params->inputfile = argv[i++];
  106. }
  107. }
  108. else if (argv[i][1] == 'f')
  109. {
  110. if (++i < argc)
  111. {
  112. params->format = atoi(argv[i++]);
  113. }
  114. }
  115. else if (argv[i][1] == 'w')
  116. {
  117. if (++i < argc)
  118. {
  119. params->width = atoi(argv[i++]);
  120. }
  121. }
  122. else if (argv[i][1] == 'h')
  123. {
  124. if (++i < argc)
  125. {
  126. params->height = atoi(argv[i++]);
  127. }
  128. }
  129. else if (argv[i][1] == 's')
  130. {
  131. if (++i < argc)
  132. {
  133. params->stride = atoi(argv[i++]);
  134. }
  135. }
  136. else if (argv[i][1] == 'n')
  137. {
  138. if (++i < argc)
  139. {
  140. params->frames = atoi(argv[i++]);
  141. }
  142. }
  143. }
  144. if ((params->format == PLINK_COLOR_FormatYUV420SemiPlanarP010 ||
  145. params->format == PLINK_COLOR_FormatRawBayer10bit ||
  146. params->format == PLINK_COLOR_FormatRawBayer12bit) &&
  147. params->stride < params->width*2)
  148. {
  149. params->stride = params->width*2;
  150. }
  151. else if (params->stride < params->width)
  152. {
  153. params->stride = params->width;
  154. }
  155. }
  156. int checkParams(ServerParams *params)
  157. {
  158. if (params->plinkname == NULL ||
  159. params->inputfile == NULL ||
  160. params->format == PLINK_COLOR_FormatUnused ||
  161. params->width == 0 ||
  162. params->height == 0 ||
  163. params->stride == 0)
  164. return -1;
  165. return 0;
  166. }
  167. int getBufferSize(ServerParams *params)
  168. {
  169. int size = 0;
  170. switch (params->format)
  171. {
  172. case PLINK_COLOR_FormatYUV420Planar:
  173. case PLINK_COLOR_FormatYUV420SemiPlanar:
  174. size = params->stride * params->height * 3 / 2;
  175. break;
  176. case PLINK_COLOR_FormatYUV420SemiPlanarP010:
  177. size = params->stride * params->height * 3;
  178. break;
  179. case PLINK_COLOR_FormatRawBayer10bit:
  180. case PLINK_COLOR_FormatRawBayer12bit:
  181. size = params->stride * params->height;
  182. break;
  183. default:
  184. size = 0;
  185. }
  186. return size;
  187. }
  188. void AllocateBuffers(PictureBuffer picbuffers[NUM_OF_BUFFERS], unsigned int size, void *vmem)
  189. {
  190. unsigned int buffer_size = (size + 0xFFF) & ~0xFFF;
  191. VmemParams params;
  192. params.size = buffer_size;
  193. params.flags = VMEM_FLAG_CONTIGUOUS | VMEM_FLAG_4GB_ADDR;
  194. for (int i = 0; i < NUM_OF_BUFFERS; i++)
  195. {
  196. params.fd = 0;
  197. VMEM_allocate(vmem, &params);
  198. VMEM_mmap(vmem, &params);
  199. VMEM_export(vmem, &params);
  200. printf("[SERVER] mmap %p from %x with size %d, dma-buf fd %d\n",
  201. params.vir_address, params.phy_address, params.size, params.fd);
  202. picbuffers[i].virtual_address = params.vir_address;
  203. picbuffers[i].bus_address = params.phy_address;
  204. picbuffers[i].size = buffer_size;
  205. picbuffers[i].fd = params.fd;
  206. }
  207. }
  208. void FreeBuffers(PictureBuffer picbuffers[NUM_OF_BUFFERS], void *vmem)
  209. {
  210. VmemParams params;
  211. memset(&params, 0, sizeof(params));
  212. for (int i = 0; i < NUM_OF_BUFFERS; i++)
  213. {
  214. close(picbuffers[i].fd);
  215. params.size = picbuffers[i].size;
  216. params.vir_address = picbuffers[i].virtual_address;
  217. params.phy_address = picbuffers[i].bus_address;
  218. VMEM_free(vmem, &params);
  219. }
  220. }
  221. void ProcessOneFrame(void *virtual_address, FILE *fp, int size)
  222. {
  223. if(virtual_address != MAP_FAILED && fp != NULL)
  224. {
  225. if (fread(virtual_address, size, 1, fp) < 1)
  226. fprintf(stderr, "ERROR: Failed to read %d bytes from file (eof %d): %s\n",
  227. size, feof(fp), strerror(errno));
  228. }
  229. }
  230. void constructYuvInfo(PlinkYuvInfo *info, ServerParams *params, unsigned int bus_address, int id)
  231. {
  232. int size_y = params->width * params->stride;
  233. int size_uv = size_y / 2;
  234. int size_yuv = size_y + size_uv;
  235. info->header.type = PLINK_TYPE_2D_YUV;
  236. info->header.size = DATA_SIZE(*info);
  237. info->header.id = id + 1;
  238. info->format = params->format;
  239. info->bus_address_y = bus_address;
  240. info->bus_address_u = info->bus_address_y + size_y;
  241. info->bus_address_v = info->bus_address_u + (size_uv / 2);
  242. info->pic_width = params->width;
  243. info->pic_height = params->height;
  244. info->stride_y = params->stride;
  245. info->stride_u =
  246. params->format == PLINK_COLOR_FormatYUV420Planar ?
  247. params->stride/2 : params->stride;
  248. info->stride_v = info->stride_u;
  249. }
  250. void constructRawInfo(PlinkRawInfo *info, ServerParams *params, unsigned int bus_address, int id)
  251. {
  252. int size_y = params->width * params->stride;
  253. int size_uv = size_y / 2;
  254. int size_yuv = size_y + size_uv;
  255. info->header.type = PLINK_TYPE_2D_RAW;
  256. info->header.size = DATA_SIZE(*info);
  257. info->header.id = id + 1;
  258. info->format = params->format;
  259. info->bus_address = bus_address;
  260. info->img_width = params->width;
  261. info->img_height = params->height;
  262. info->stride = params->stride;
  263. }
  264. int getBufferCount(PlinkPacket *pkt)
  265. {
  266. int ret = 0;
  267. for (int i = 0; i < pkt->num; i++)
  268. {
  269. PlinkDescHdr *hdr = (PlinkDescHdr *)(pkt->list[i]);
  270. if (hdr->type == PLINK_TYPE_MESSAGE)
  271. {
  272. int *data = (int *)(pkt->list[i] + DATA_HEADER_SIZE);
  273. if (*data == PLINK_EXIT_CODE)
  274. {
  275. ret |= 0x80000000; // set bit 31 to 1 to indicate 'exit'
  276. }
  277. else if (*data >= 0)
  278. ret++;
  279. }
  280. }
  281. return ret;
  282. }
  283. void retreiveSentBuffers(PlinkHandle plink, PlinkChannel *channel)
  284. {
  285. PlinkStatus sts = PLINK_STATUS_OK;
  286. while (channel->available_bufs < NUM_OF_BUFFERS && sts == PLINK_STATUS_OK)
  287. {
  288. do
  289. {
  290. sts = PLINK_recv(plink, channel->id, &channel->pkt);
  291. int count = getBufferCount(&channel->pkt);
  292. if (count > 0)
  293. {
  294. channel->available_bufs += count;
  295. }
  296. } while (sts == PLINK_STATUS_MORE_DATA);
  297. }
  298. }
  299. int main(int argc, char **argv) {
  300. PlinkStatus sts = PLINK_STATUS_OK;
  301. ServerParams params;
  302. PlinkChannel channel[2];
  303. PlinkHandle plink = NULL;
  304. PlinkYuvInfo pic = {0};
  305. PlinkRawInfo img = {0};
  306. PlinkMsg msg;
  307. parseParams(argc, argv, &params);
  308. if (checkParams(&params) != 0)
  309. {
  310. printUsage(argv[0]);
  311. return 0;
  312. }
  313. FILE *fp = fopen(params.inputfile, "rb");
  314. if (fp == NULL)
  315. errExit("fopen");
  316. void *vmem = NULL;
  317. if (VMEM_create(&vmem) != VMEM_STATUS_OK)
  318. errExit("Failed to create VMEM.");
  319. int width = params.width;
  320. int height = params.height;
  321. int stride = params.stride;
  322. int frames = params.frames;
  323. int size = getBufferSize(&params);
  324. if (size == 0)
  325. errExit("Wrong format or wrong resolution.");
  326. PictureBuffer picbuffers[NUM_OF_BUFFERS];
  327. AllocateBuffers(picbuffers, size, vmem);
  328. sts = PLINK_create(&plink, params.plinkname, PLINK_MODE_SERVER);
  329. memset(&channel[0], 0, sizeof(channel[0]));
  330. channel[0].available_bufs = NUM_OF_BUFFERS;
  331. sts = PLINK_connect(plink, &channel[0].id);
  332. int frmcnt = 0;
  333. do {
  334. int sendid = channel[0].sendid;
  335. ProcessOneFrame(picbuffers[sendid].virtual_address, fp, size);
  336. if (params.format == PLINK_COLOR_FormatRawBayer8bit ||
  337. params.format == PLINK_COLOR_FormatRawBayer10bit ||
  338. params.format == PLINK_COLOR_FormatRawBayer12bit)
  339. {
  340. constructRawInfo(&img, &params, picbuffers[sendid].bus_address, sendid);
  341. printf("[SERVER] Processed frame %d 0x%010llx: %dx%d, stride %d\n",
  342. sendid, img.bus_address, img.img_width, img.img_height, img.stride);
  343. channel[0].pkt.list[0] = &img;
  344. }
  345. else // YUV
  346. {
  347. constructYuvInfo(&pic, &params, picbuffers[sendid].bus_address, sendid);
  348. printf("[SERVER] Processed frame %d 0x%010llx: %dx%d, stride = luma %d, chroma %d\n",
  349. sendid, pic.bus_address_y,
  350. pic.pic_width, pic.pic_height,
  351. pic.stride_y, pic.stride_u);
  352. channel[0].pkt.list[0] = &pic;
  353. }
  354. channel[0].pkt.num = 1;
  355. channel[0].pkt.fd = picbuffers[sendid].fd;
  356. sts = PLINK_send(plink, channel[0].id, &channel[0].pkt);
  357. channel[0].sendid = (channel[0].sendid + 1) % NUM_OF_BUFFERS;
  358. channel[0].available_bufs -= 1;
  359. int timeout = 0;
  360. if (channel[0].available_bufs == 0)
  361. timeout = 60000; // wait up to 60 seconds if buffers are used up
  362. if (PLINK_wait(plink, channel[0].id, timeout) == PLINK_STATUS_OK)
  363. {
  364. do
  365. {
  366. sts = PLINK_recv(plink, channel[0].id, &channel[0].pkt);
  367. int count = getBufferCount(&channel[0].pkt);
  368. if (count < 0)
  369. channel[0].exit = 1;
  370. channel[0].available_bufs += count;
  371. } while (sts == PLINK_STATUS_MORE_DATA);
  372. }
  373. frmcnt++;
  374. } while (channel[0].exit == 0 && frmcnt < frames);
  375. cleanup:
  376. msg.header.type = PLINK_TYPE_MESSAGE;
  377. msg.header.size = DATA_SIZE(PlinkMsg);
  378. msg.msg = PLINK_EXIT_CODE;
  379. channel[0].pkt.list[0] = &msg;
  380. channel[0].pkt.num = 1;
  381. channel[0].pkt.fd = PLINK_INVALID_FD;
  382. sts = PLINK_send(plink, channel[0].id, &channel[0].pkt);
  383. retreiveSentBuffers(plink, &channel[0]);
  384. PLINK_recv_ex(plink, channel[0].id, &channel[0].pkt, 1000);
  385. //sleep(1); // Sleep one second to make sure client is ready for exit
  386. if (vmem)
  387. FreeBuffers(picbuffers, vmem);
  388. PLINK_close(plink, PLINK_CLOSE_ALL);
  389. VMEM_destroy(vmem);
  390. if (fp != NULL)
  391. fclose(fp);
  392. exit(EXIT_SUCCESS);
  393. }