ffmpeg_input_test.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2021 StarFive Technology Co., Ltd.
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include <getopt.h>
  10. #include <signal.h>
  11. #include <inttypes.h>
  12. #include <stdbool.h>
  13. #include <libv4l2.h>
  14. #include <poll.h>
  15. #include <libavcodec/avcodec.h>
  16. #include <libavdevice/avdevice.h>
  17. #include <libavformat/avformat.h>
  18. #include <libavformat/avio.h>
  19. #include "common.h"
  20. #include "stf_drm.h"
  21. #include "stf_log.h"
  22. #define DRM_DEVICE_NAME "/dev/dri/card0"
  23. #define V4L2_DFT_DEVICE_NAME "/dev/video0"
  24. #define FFMPEG_INPUT_NAME "video4linux2"
  25. typedef struct enum_value_t {
  26. int value;
  27. const char *name;
  28. } enum_value_t;
  29. static const enum_value_t g_disp_values[] = {
  30. { STF_DISP_NONE, "NONE"},
  31. // { STF_DISP_FB, "FB"},
  32. { STF_DISP_DRM, "DRM"}
  33. };
  34. static const enum_value_t g_iomthd_values[] = {
  35. { IO_METHOD_MMAP, "MMAP"},
  36. { IO_METHOD_USERPTR, "USERPTR"},
  37. { IO_METHOD_DMABUF, "DMABUF"},
  38. { IO_METHOD_READ, "READ"}
  39. };
  40. typedef struct {
  41. DRMParam_t drm_param;
  42. char *device_name; // v4l2 device name
  43. char* out_file; // save file
  44. FILE* out_fp; // for save file
  45. uint32_t format; // V4L2_PIX_FMT_RGB565
  46. uint32_t width;
  47. uint32_t height;
  48. uint32_t fps;
  49. uint32_t image_size;
  50. enum STF_DISP_TYPE disp_type;
  51. enum IOMethod io_mthd;
  52. int continuous;
  53. uint8_t jpegQuality;
  54. int dmabufs[BUFCOUNT]; // for dmabuf use, mmap not use it
  55. AVFormatContext* format_ctx;
  56. AVCodecContext* vcodec_ctx;
  57. AVPacket* packet;
  58. } ConfigParam_t;
  59. ConfigParam_t *gp_cfg_param = NULL;
  60. static void sync_handler (int fd, unsigned int frame,
  61. unsigned int sec, unsigned int usec,
  62. void *data)
  63. {
  64. int *waiting;
  65. waiting = data;
  66. *waiting = 0;
  67. }
  68. int sync_drm_frame(int buf_id)
  69. {
  70. int ret;
  71. int waiting = 1;
  72. struct pollfd* fds = NULL;
  73. uint32_t nfds = 0;
  74. drmEventContext evctxt = {
  75. .version = DRM_EVENT_CONTEXT_VERSION,
  76. .page_flip_handler = sync_handler,
  77. .vblank_handler = NULL,
  78. };
  79. ret = drmModePageFlip (gp_cfg_param->drm_param.fd, gp_cfg_param->drm_param.dev_head->crtc_id,
  80. gp_cfg_param->drm_param.dev_head->bufs[buf_id].fb_id,
  81. DRM_MODE_PAGE_FLIP_EVENT, &waiting);
  82. if (ret) {
  83. goto pageflip_failed;
  84. }
  85. nfds = 1;
  86. fds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds);
  87. memset(fds, 0, sizeof(struct pollfd) * nfds);
  88. fds[0].fd = gp_cfg_param->drm_param.fd;
  89. fds[0].events = POLLIN;
  90. while (waiting) {
  91. do {
  92. ret = poll(fds, nfds, 3000);
  93. } while (ret == -1 && (errno == EAGAIN || errno == EINTR));
  94. ret = drmHandleEvent(gp_cfg_param->drm_param.fd, &evctxt);
  95. if (ret) {
  96. goto event_failed;
  97. }
  98. }
  99. return 0;
  100. pageflip_failed:
  101. {
  102. LOG(STF_LEVEL_ERR, "drmModePageFlip failed: %s (%d)\n",
  103. strerror(errno), errno);
  104. return 1;
  105. }
  106. event_failed:
  107. {
  108. LOG(STF_LEVEL_ERR, "drmHandleEvent failed: %s (%d)\n",
  109. strerror(errno), errno);
  110. return 1;
  111. }
  112. }
  113. void mainloop(void)
  114. {
  115. AVFormatContext* fmtCtx = gp_cfg_param->format_ctx;
  116. AVPacket* packet = gp_cfg_param->packet;
  117. FILE* fp = gp_cfg_param->out_fp;
  118. uint32_t buf_id = 0;
  119. while (gp_cfg_param->continuous) {
  120. av_read_frame(fmtCtx, packet);
  121. if (STF_DISP_DRM == gp_cfg_param->disp_type) {
  122. LOG(STF_LEVEL_TRACE, "data length = %d, drm buf length = %d\n", packet->size,
  123. gp_cfg_param->drm_param.dev_head->bufs[buf_id].size);
  124. memcpy(gp_cfg_param->drm_param.dev_head->bufs[buf_id].buf, packet->data, packet->size);
  125. sync_drm_frame(buf_id++);
  126. if (buf_id >= BUFCOUNT) {
  127. buf_id = 0;
  128. }
  129. }
  130. if (fp) {
  131. LOG(STF_LEVEL_INFO, "save file: %s\n", gp_cfg_param->out_file);
  132. fwrite(packet->data, 1, packet->size, fp);
  133. }
  134. av_packet_unref(packet);
  135. }
  136. }
  137. static void alloc_default_config(ConfigParam_t **pp_data)
  138. {
  139. ConfigParam_t *cfg_param = NULL;
  140. cfg_param = malloc(sizeof(*cfg_param));
  141. if (!cfg_param) {
  142. errno_exit("malloc");
  143. }
  144. memset(cfg_param, 0, sizeof(*cfg_param));
  145. cfg_param->device_name = V4L2_DFT_DEVICE_NAME;
  146. cfg_param->io_mthd = IO_METHOD_MMAP;
  147. cfg_param->format = V4L2_PIX_FMT_NV12;
  148. cfg_param->continuous = 1;
  149. *pp_data = cfg_param;
  150. }
  151. static void usage(FILE* fp, int argc, char** argv)
  152. {
  153. fprintf(fp,
  154. "Usage: %s [options]\n\n"
  155. "Options:\n"
  156. "-d | --device name Video device name [default /dev/video0]\n"
  157. "-h | --help Print this message\n"
  158. "-o | --output Set output filename\n"
  159. "-W | --width Set v4l2 image width, default 1920\n"
  160. "-H | --height Set v4l2 image height, default 1080\n"
  161. "-I | --interval Set frame interval (fps) (-1 to skip)\n"
  162. "-c | --continuous Do continous capture, stop with SIGINT.\n"
  163. "-v | --version Print version\n"
  164. "-f | --format image format, default 4\n"
  165. " 0: V4L2_PIX_FMT_RGB565\n"
  166. " 1: V4L2_PIX_FMT_RGB24\n"
  167. " 2: V4L2_PIX_FMT_YUV420\n"
  168. " 3: V4L2_PIX_FMT_YUYV\n"
  169. " 4: V4L2_PIX_FMT_NV21\n"
  170. " 5: V4L2_PIX_FMT_NV12\n"
  171. " 6: V4L2_PIX_FMT_YVYU\n"
  172. " 7: V4L2_PIX_FMT_SRGGB12\n"
  173. " 8: V4L2_PIX_FMT_SGRBG12\n"
  174. " 9: V4L2_PIX_FMT_SGBRG12\n"
  175. " 10: V4L2_PIX_FMT_SBGGR12\n"
  176. " default: V4L2_PIX_FMT_RGB565\n"
  177. "-t | --distype set display type, default 0\n"
  178. " 0: Not display\n"
  179. " 1: Use DRM Display\n"
  180. "\n"
  181. "Eg:\n"
  182. "\t sensor : ffmpeg_input_test -d /dev/video2 -f 5 -W 640 -H 480 -I 30 -t 1\n"
  183. "\t uvc cam: ffmpeg_input_test -d /dev/video5 -f 3 -W 640 -H 480 -I 30 -t 1\n"
  184. "\n"
  185. "Open debug log level: \n"
  186. "\t export V4L2_DEBUG=3\n"
  187. "\t default level 1, level range 0 ~ 7\n"
  188. "",
  189. argv[0]);
  190. }
  191. static const char short_options [] = "d:ho:W:H:I:vcf:t:X:Y:";
  192. static const struct option long_options [] = {
  193. { "device", required_argument, NULL, 'd' },
  194. { "help", no_argument, NULL, 'h' },
  195. { "output", required_argument, NULL, 'o' },
  196. { "width", required_argument, NULL, 'W' },
  197. { "height", required_argument, NULL, 'H' },
  198. { "interval", required_argument, NULL, 'I' },
  199. { "version", no_argument, NULL, 'v' },
  200. { "continuous", no_argument, NULL, 'c' },
  201. { "format", required_argument, NULL, 'f' },
  202. { "distype", required_argument, NULL, 't' },
  203. { 0, 0, 0, 0 }
  204. };
  205. void parse_options(int argc, char **argv, ConfigParam_t *cfg_param)
  206. {
  207. int index, c = 0;
  208. int value = 0;
  209. while ((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
  210. switch (c) {
  211. case 0: /* getopt_long() flag */
  212. break;
  213. case 'd':
  214. cfg_param->device_name = strdup(optarg);
  215. break;
  216. case 'h':
  217. usage(stdout, argc, argv);
  218. exit(EXIT_SUCCESS);
  219. case 'o':
  220. // set filename
  221. cfg_param->out_file = strdup(optarg);
  222. LOG(STF_LEVEL_INFO, "save file: %s\n", cfg_param->out_file);
  223. break;
  224. case 'W':
  225. // set v4l2 width
  226. cfg_param->width = atoi(optarg);
  227. break;
  228. case 'H':
  229. // set v4l2 height
  230. cfg_param->height = atoi(optarg);
  231. break;
  232. case 'I':
  233. // set fps
  234. cfg_param->fps = atoi(optarg);
  235. break;
  236. case 'c':
  237. // set flag for continuous capture, interuptible by sigint
  238. cfg_param->continuous = 1;
  239. // InstallSIGINTHandler();
  240. break;
  241. case 'v':
  242. printf("Version: %s\n", TEST_VERSION);
  243. exit(EXIT_SUCCESS);
  244. break;
  245. case 'f':
  246. LOG(STF_LEVEL_INFO, "v4l2 format: %s\n", optarg);
  247. value = atoi(optarg);
  248. LOG(STF_LEVEL_INFO, "v4l2 format: %d\n", value);
  249. switch (value) {
  250. case 0:
  251. value = V4L2_PIX_FMT_RGB565;
  252. break;
  253. case 1:
  254. value = V4L2_PIX_FMT_RGB24;
  255. break;
  256. case 2:
  257. value = V4L2_PIX_FMT_YUV420;
  258. break;
  259. case 3:
  260. value = V4L2_PIX_FMT_YUYV;
  261. break;
  262. case 4:
  263. value = V4L2_PIX_FMT_NV21;
  264. break;
  265. case 5:
  266. value = V4L2_PIX_FMT_NV12;
  267. break;
  268. case 6:
  269. value = V4L2_PIX_FMT_YVYU;
  270. break;
  271. case 7:
  272. value = V4L2_PIX_FMT_SRGGB12;
  273. break;
  274. case 8:
  275. value = V4L2_PIX_FMT_SGRBG12;
  276. break;
  277. case 9:
  278. value = V4L2_PIX_FMT_SGBRG12;
  279. break;
  280. case 10:
  281. value = V4L2_PIX_FMT_SBGGR12;
  282. break;
  283. default:
  284. value = V4L2_PIX_FMT_RGB565;
  285. break;
  286. }
  287. cfg_param->format = value;
  288. break;
  289. case 't':
  290. value = atoi(optarg);
  291. if (value < STF_DISP_NONE || value > STF_DISP_DRM) {
  292. LOG(STF_LEVEL_ERR, "Display Type %d is out of range [%d, %d]\n", value,
  293. STF_DISP_NONE, STF_DISP_DRM);
  294. exit(EXIT_FAILURE);
  295. }
  296. LOG(STF_LEVEL_INFO, "Display Type: %s\n", g_disp_values[value].name);
  297. cfg_param->disp_type = value;
  298. break;
  299. default:
  300. usage(stderr, argc, argv);
  301. exit(EXIT_FAILURE);
  302. }
  303. }
  304. }
  305. void StopContCapture(int sig_id)
  306. {
  307. LOG(STF_LEVEL_INFO, "stoping continuous capture\n");
  308. gp_cfg_param->continuous = 0;
  309. }
  310. void signal_handler()
  311. {
  312. struct sigaction sa;
  313. CLEAR(sa);
  314. sa.sa_handler = StopContCapture;
  315. if (sigaction(SIGINT, &sa, 0) != 0) {
  316. LOG(STF_LEVEL_ERR, "could not install SIGINT handler, continuous capture disabled\n");
  317. gp_cfg_param->continuous = 0;
  318. }
  319. }
  320. int main(int argc, char **argv)
  321. {
  322. AVFormatContext* fmtCtx = NULL;
  323. AVInputFormat* inputFmt;
  324. AVCodecContext* pCodecCtx;
  325. AVCodec* pCodec;
  326. int videoindex, i;
  327. char str_data[32] = {0};
  328. AVDictionary *options = NULL;
  329. // init param and log
  330. signal_handler();
  331. init_log();
  332. alloc_default_config(&gp_cfg_param);
  333. parse_options(argc, argv, gp_cfg_param);
  334. // check_cfg_params(gp_cfg_param);
  335. // init ffmpeg env
  336. av_log_set_level(AV_LOG_TRACE);
  337. avcodec_register_all();
  338. avdevice_register_all();
  339. inputFmt = av_find_input_format(FFMPEG_INPUT_NAME);
  340. if (inputFmt == NULL) {
  341. LOG(STF_LEVEL_ERR, "can not find_input_format\n");
  342. exit(EXIT_FAILURE);
  343. }
  344. // open and set parameter to v4l2 device
  345. av_dict_set(&options, "f", "v4l2", 0); // speed up probe process
  346. if (V4L2_PIX_FMT_NV12 == gp_cfg_param->format) { // format
  347. av_dict_set(&options, "input_format", "nv12", 0);
  348. } else if (V4L2_PIX_FMT_YUYV == gp_cfg_param->format) {
  349. av_dict_set(&options, "input_format", "yuyv422", 0);
  350. } else {
  351. LOG(STF_LEVEL_ERR, "Current only support nv12 format\n");
  352. exit(EXIT_FAILURE);
  353. }
  354. if (gp_cfg_param->width && gp_cfg_param->height) {
  355. snprintf(str_data, 32, "%d*%d", gp_cfg_param->width, gp_cfg_param->height);
  356. av_dict_set(&options, "video_size", str_data, 0); // resolution eg: "640*480"
  357. }
  358. if (gp_cfg_param->fps) {
  359. snprintf(str_data, 32, "%d", gp_cfg_param->fps);
  360. av_dict_set(&options, "framerate", str_data, 0); // framerate eg: "15"
  361. }
  362. if (avformat_open_input(&fmtCtx, gp_cfg_param->device_name, inputFmt, &options) < 0) {
  363. LOG(STF_LEVEL_ERR, "can not open input_file\n");
  364. exit(EXIT_FAILURE);
  365. }
  366. av_dict_free(&options);
  367. /* print device information*/
  368. av_dump_format(fmtCtx, 0, gp_cfg_param->device_name, 0);
  369. videoindex = -1;
  370. for (i = 0; i < fmtCtx->nb_streams; i++) {
  371. if (fmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  372. videoindex = i;
  373. break;
  374. }
  375. }
  376. if (videoindex == -1) {
  377. LOG(STF_LEVEL_ERR, "fail to find a video stream\n");
  378. exit(EXIT_FAILURE);
  379. }
  380. pCodecCtx = fmtCtx->streams[videoindex]->codec;
  381. pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
  382. LOG(STF_LEVEL_INFO, "picture width = %d \n", pCodecCtx->width);
  383. LOG(STF_LEVEL_INFO, "picture height = %d \n", pCodecCtx->height);
  384. LOG(STF_LEVEL_INFO, "Pixel format = %d \n", pCodecCtx->pix_fmt);
  385. LOG(STF_LEVEL_INFO, "codec_id = %d \n", pCodecCtx->codec_id); // AV_CODEC_ID_RAWVIDEO
  386. if (gp_cfg_param->out_file && !gp_cfg_param->out_fp) {
  387. gp_cfg_param->out_fp = fopen(gp_cfg_param->out_file, "wb");
  388. if (!gp_cfg_param->out_fp) {
  389. LOG(STF_LEVEL_ERR, "fopen file failed %s\n", gp_cfg_param->out_file);
  390. exit(EXIT_FAILURE);
  391. }
  392. }
  393. gp_cfg_param->packet = (AVPacket*)av_malloc(sizeof(AVPacket));
  394. gp_cfg_param->format_ctx = fmtCtx;
  395. gp_cfg_param->vcodec_ctx = pCodecCtx;
  396. if (STF_DISP_DRM == gp_cfg_param->disp_type) {
  397. stf_drm_open(&gp_cfg_param->drm_param, DRM_DEVICE_NAME, gp_cfg_param->io_mthd);
  398. stf_drm_init(&gp_cfg_param->drm_param, gp_cfg_param->vcodec_ctx->width,
  399. gp_cfg_param->vcodec_ctx->height, gp_cfg_param->vcodec_ctx->pix_fmt,
  400. gp_cfg_param->io_mthd, gp_cfg_param->dmabufs,
  401. sizeof(gp_cfg_param->dmabufs) / sizeof(gp_cfg_param->dmabufs[0]));
  402. }
  403. // process frames
  404. mainloop();
  405. // release resource
  406. if (gp_cfg_param->out_fp) {
  407. fclose(gp_cfg_param->out_fp);
  408. }
  409. if (gp_cfg_param->packet) {
  410. av_free_packet(gp_cfg_param->packet);
  411. }
  412. if (gp_cfg_param->format_ctx) {
  413. avformat_close_input(&gp_cfg_param->format_ctx);
  414. }
  415. if (STF_DISP_DRM == gp_cfg_param->disp_type) {
  416. stf_drm_close(&gp_cfg_param->drm_param);
  417. }
  418. deinit_log();
  419. free(gp_cfg_param);
  420. return 0;
  421. }