Guest User

nvfbc_loop.c

a guest
Jul 16th, 2021
155
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*!
  2.  * \brief
  3.  * Demonstrates how to use NvFBC to grab frames to an OpenGL texture in
  4.  * video memory and send them to the HW encoder using NvEncodeAPI's OpenGL
  5.  * interface.
  6.  *
  7.  * \file
  8.  * This sample demonstrates the following features:
  9.  * - Capture to video memory (texture) using OpenGL interop;
  10.  * - Manage a GL context externally, and pass it to NvFBC;
  11.  * - Disable automatic modeset recovery;
  12.  * - Register the texture for NvEncodeAPI's use;
  13.  * - Encode the frame in the texture using the NvEncodeAPI's OpenGL interface
  14.  *
  15.  * \copyright
  16.  * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
  17.  *
  18.  * Permission is hereby granted, free of charge, to any person obtaining a
  19.  * copy of this software and associated documentation files (the "Software"),
  20.  * to deal in the Software without restriction, including without limitation
  21.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  22.  * and/or sell copies of the Software, and to permit persons to whom the
  23.  * Software is furnished to do so, subject to the following conditions:
  24.  *
  25.  * The above copyright notice and this permission notice shall be included in
  26.  * all copies or substantial portions of the Software.
  27.  *
  28.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  29.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  30.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  31.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  32.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  33.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  34.  * DEALINGS IN THE SOFTWARE.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <stdint.h>
  40. #include <dlfcn.h>
  41. #include <string.h>
  42. #include <getopt.h>
  43. #include <unistd.h>
  44.  
  45. #include <GL/gl.h>
  46. #include <GL/glx.h>
  47. #include <X11/Xlib.h>
  48.  
  49. #include "NvFBC.h"
  50. #include "nvEncodeAPI.h"
  51. #include "NvFBCUtils.h"
  52.  
  53. #define APP_VERSION 1
  54.  
  55. #define LIB_NVFBC_NAME     "libnvidia-fbc.so.1"
  56. #define LIB_ENCODEAPI_NAME "libnvidia-encode.so.1"
  57.  
  58. #define N_FRAMES 1
  59.  
  60. /*
  61.  * Global variables
  62.  */
  63. GLXContext glxCtx       = None;
  64. GLXFBConfig glxFBConfig = None;
  65. NV_ENCODE_API_FUNCTION_LIST pEncFn;
  66.  
  67. /*
  68.  * NvEncodeAPI entry point
  69.  */
  70. typedef NVENCSTATUS (NVENCAPI *PFNNVENCODEAPICREATEINSTANCEPROC)(NV_ENCODE_API_FUNCTION_LIST *);
  71.  
  72. enum codecType {
  73.     CODEC_H264,
  74.     CODEC_HEVC
  75. };
  76.  
  77. /**
  78.  * Prints usage information.
  79.  */
  80. static void usage(const char *pname)
  81. {
  82.     printf("Usage: %s [options]\n", pname);
  83.     printf("\n");
  84.     printf("Options:\n");
  85.     printf("  --help|-h         This message\n");
  86.     printf("  --frames|-f <n>   Number of frames to capture (default: %u)\n",
  87.            N_FRAMES);
  88.     printf("  --size|-s <w>x<h> Size of the captured frames\n");
  89.     printf("                    (default: size of the framebuffer)\n");
  90.     printf("  --codec|-c <str>  Codec to use\n");
  91.     printf("                    Can be 'h264' or 'hevc'\n");
  92.     printf("                    (default: 'h264')\n");
  93.     printf("  --output|-o <str> Name of the output file \n");
  94.     printf("                    (default: \"output\"\n");
  95.     printf("                    The codec used will be appended to this\n");
  96.     printf("                    name\n");
  97. }
  98.  
  99. /**
  100.  * Creates an OpenGL context.
  101.  *
  102.  * This context will then be passed to NvFBC for its internal use.
  103.  *
  104.  * \param [out] *glxCtx
  105.  *   The created OpenGL context.
  106.  * \param [out] *glxFbConfig
  107.  *   The used framebuffer configuration.
  108.  *
  109.  * \return
  110.  *   NVFBC_TRUE in case of success, NVFBC_FALSE otherwise.
  111.  */
  112. static NVFBC_BOOL gl_init(void)
  113. {
  114.     Display *dpy        = None;
  115.     Pixmap pixmap       = None;
  116.     GLXPixmap glxPixmap = None;
  117.     GLXFBConfig *fbConfigs;
  118.     Bool res;
  119.     int n;
  120.  
  121.     static int initialized = False;
  122.     if (initialized) {
  123.     return True;
  124.     }
  125.  
  126.     int attribs[] = {
  127.         GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT,
  128.         GLX_BIND_TO_TEXTURE_RGBA_EXT, 1,
  129.         GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
  130.         None
  131.     };
  132.  
  133.     dpy = XOpenDisplay(NULL);
  134.     if (dpy == None) {
  135.         fprintf(stderr, "Unable to open display\n");
  136.         return NVFBC_FALSE;
  137.     }
  138.  
  139.     fbConfigs = glXChooseFBConfig(dpy, DefaultScreen(dpy), attribs, &n);
  140.     if (!fbConfigs) {
  141.         fprintf(stderr, "Unable to find FB configs\n");
  142.         return NVFBC_FALSE;
  143.     }
  144.  
  145.     glxCtx = glXCreateNewContext(dpy, fbConfigs[0], GLX_RGBA_TYPE, None, True);
  146.     if (glxCtx == None) {
  147.         fprintf(stderr, "Unable to create GL context\n");
  148.         return NVFBC_FALSE;
  149.     }
  150.  
  151.     pixmap = XCreatePixmap(dpy, XDefaultRootWindow(dpy), 1, 1, DisplayPlanes(dpy, XDefaultScreen(dpy)));
  152.     if (pixmap == None) {
  153.         fprintf(stderr, "Unable to create pixmap\n");
  154.         return NVFBC_FALSE;
  155.     }
  156.  
  157.     glxPixmap = glXCreatePixmap(dpy, fbConfigs[0], pixmap, NULL);
  158.     if (glxPixmap == None) {
  159.         fprintf(stderr, "Unable to create GLX pixmap\n");
  160.         return NVFBC_FALSE;
  161.     }
  162.  
  163.     res = glXMakeCurrent(dpy, glxPixmap, glxCtx);
  164.     if (!res) {
  165.         fprintf(stderr, "Unable to make context current\n");
  166.         return NVFBC_FALSE;
  167.     }
  168.  
  169.     glxFBConfig = fbConfigs[0];
  170.  
  171.     XFree(fbConfigs);
  172.     initialized = True;
  173.  
  174.     return NVFBC_TRUE;
  175. }
  176.  
  177.  
  178.  
  179. /**
  180.  * Initializes the NvFBC library and creates an NvFBC instance.
  181.  *
  182.  * Creates and sets up a capture session to video memory.
  183.  *
  184.  * Creates and sets up an encode session and initializes the encoder with
  185.  * parameters for generating an H.264 stream.
  186.  *
  187.  * Captures frames, encodes them and writes them out to a file (output.h264)
  188.  */
  189. int test(int argc, char *argv[])
  190. {
  191.     static struct option longopts[] = {
  192.         { "frames", required_argument, NULL, 'f' },
  193.         { "size", required_argument, NULL, 's' },
  194.         { "codec", required_argument, NULL, 'c' },
  195.         { "output", required_argument, NULL, 'o' },
  196.         { NULL, 0, NULL, 0 }
  197.     };
  198.  
  199.     int opt, ret;
  200.     unsigned int n = 0, nFrames = N_FRAMES;
  201.     NVFBC_SIZE frameSize = { 0, 0 };
  202.  
  203.     void *libNVFBC = NULL, *libEnc = NULL;
  204.  
  205.     PNVFBCCREATEINSTANCE NvFBCCreateInstance_ptr = NULL;
  206.     PFNNVENCODEAPICREATEINSTANCEPROC NvEncodeAPICreateInstance = NULL;
  207.     NVFBC_API_FUNCTION_LIST pFn;
  208.  
  209.     NVFBCSTATUS fbcStatus;
  210.     NVFBC_BOOL fbcBool;
  211.     NVENCSTATUS encStatus;
  212.  
  213.     NVFBC_SESSION_HANDLE fbcHandle;
  214.     NVFBC_CREATE_HANDLE_PARAMS createHandleParams;
  215.     NVFBC_DESTROY_HANDLE_PARAMS destroyHandleParams;
  216.  
  217.     NvFBCUtilsPrintVersions(APP_VERSION);
  218.  
  219.     /*
  220.      * Parse the command line.
  221.      */
  222.     while ((opt = getopt_long(argc, argv, "hf:s:c:o:", longopts, NULL)) != -1) {
  223.         switch (opt) {
  224.             case 'f':
  225.                 nFrames = (unsigned int) atoi(optarg);
  226.                 break;
  227.             case 's':
  228.                 ret = sscanf(optarg, "%ux%u", &frameSize.w, &frameSize.h);
  229.                 if (ret != 2) {
  230.                     fprintf(stderr, "Invalid size format: '%s'\n", optarg);
  231.                     return EXIT_FAILURE;
  232.                 }
  233.                 break;
  234.             case 'h':
  235.             default:
  236.                 usage(argv[0]);
  237.                 return EXIT_SUCCESS;
  238.         }
  239.     }
  240.  
  241.     /*
  242.      * Dynamically load the NvFBC library.
  243.      */
  244.     libNVFBC = dlopen(LIB_NVFBC_NAME, RTLD_NOW);
  245.     if (libNVFBC == NULL) {
  246.         fprintf(stderr, "Unable to open '%s'\n", LIB_NVFBC_NAME);
  247.         return EXIT_FAILURE;
  248.     }
  249.  
  250.     /*
  251.      * Dynamically load the NvEncodeAPI library.
  252.      */
  253.     libEnc = dlopen(LIB_ENCODEAPI_NAME, RTLD_NOW);
  254.     if (libNVFBC == NULL) {
  255.         fprintf(stderr, "Unable to open '%s'\n", LIB_ENCODEAPI_NAME);
  256.         return EXIT_FAILURE;
  257.     }
  258.  
  259.     /*
  260.      * Initialize OpenGL.
  261.      */
  262.     fbcBool = gl_init();
  263.     if (fbcBool != NVFBC_TRUE) {
  264.         return EXIT_FAILURE;
  265.     }
  266.  
  267.     /*
  268.      * Resolve the 'NvFBCCreateInstance' symbol that will allow us to get
  269.      * the API function pointers.
  270.      */
  271.     NvFBCCreateInstance_ptr =
  272.         (PNVFBCCREATEINSTANCE) dlsym(libNVFBC, "NvFBCCreateInstance");
  273.     if (NvFBCCreateInstance_ptr == NULL) {
  274.         fprintf(stderr, "Unable to resolve symbol 'NvFBCCreateInstance'\n");
  275.         return EXIT_FAILURE;
  276.     }
  277.  
  278.     /*
  279.      * Create an NvFBC instance.
  280.      *
  281.      * API function pointers are accessible through pFn.
  282.      */
  283.     memset(&pFn, 0, sizeof(pFn));
  284.  
  285.     pFn.dwVersion = NVFBC_VERSION;
  286.  
  287.     fbcStatus = NvFBCCreateInstance_ptr(&pFn);
  288.     if (fbcStatus != NVFBC_SUCCESS) {
  289.         fprintf(stderr, "Unable to create NvFBC instance (status: %d)\n",
  290.                 fbcStatus);
  291.         return EXIT_FAILURE;
  292.     }
  293.  
  294.     /*
  295.      * Resolve the 'NvEncodeAPICreateInstance' symbol that will allow us to get
  296.      * the API function pointers.
  297.      */
  298.     NvEncodeAPICreateInstance =
  299.         (PFNNVENCODEAPICREATEINSTANCEPROC) dlsym(libEnc, "NvEncodeAPICreateInstance");
  300.     if (NvEncodeAPICreateInstance == NULL) {
  301.         fprintf(stderr, "Unable to resolve symbol 'NvEncodeAPICreateInstance'\n");
  302.         return EXIT_FAILURE;
  303.     }
  304.  
  305.     /*
  306.      * Create an NvEncodeAPI instance.
  307.      *
  308.      * API function pointers are accessible through pEncFn.
  309.      */
  310.     memset(&pEncFn, 0, sizeof(pEncFn));
  311.  
  312.     pEncFn.version = NV_ENCODE_API_FUNCTION_LIST_VER;
  313.  
  314.     encStatus = NvEncodeAPICreateInstance(&pEncFn);
  315.     if (encStatus != NV_ENC_SUCCESS) {
  316.         fprintf(stderr, "Unable to create NvEncodeAPI instance (status: %d)\n",
  317.                 encStatus);
  318.         return EXIT_FAILURE;
  319.     }
  320.  
  321.     /*
  322.      * Create a session handle that is used to identify the client.
  323.      *
  324.      * Request that the GL context is externally managed.
  325.      */
  326.     memset(&createHandleParams, 0, sizeof(createHandleParams));
  327.  
  328.     createHandleParams.dwVersion                 = NVFBC_CREATE_HANDLE_PARAMS_VER;
  329.     createHandleParams.bExternallyManagedContext = NVFBC_TRUE;
  330.     createHandleParams.glxCtx                    = glxCtx;
  331.     createHandleParams.glxFBConfig               = glxFBConfig;
  332.  
  333.     fbcStatus = pFn.nvFBCCreateHandle(&fbcHandle, &createHandleParams);
  334.     if (fbcStatus != NVFBC_SUCCESS) {
  335.         fprintf(stderr, "%s\n", pFn.nvFBCGetLastErrorStr(fbcHandle));
  336.         return EXIT_FAILURE;
  337.     }
  338.  
  339.     NVFBC_GET_STATUS_PARAMS statusParams;
  340.     NVFBC_CREATE_CAPTURE_SESSION_PARAMS createCaptureParams;
  341.     NVFBC_TOGL_SETUP_PARAMS setupParams;
  342.     NVFBC_DESTROY_CAPTURE_SESSION_PARAMS destroyCaptureParams;
  343.  
  344.     /*
  345.      * Retrieve the size of framebuffer.
  346.      */
  347.     memset(&statusParams, 0, sizeof(statusParams));
  348.  
  349.     statusParams.dwVersion = NVFBC_GET_STATUS_PARAMS_VER;
  350.  
  351.     fbcStatus = pFn.nvFBCGetStatus(fbcHandle, &statusParams);
  352.     if (fbcStatus != NVFBC_SUCCESS) {
  353.         fprintf(stderr, "%s\n", pFn.nvFBCGetLastErrorStr(fbcHandle));
  354.         goto fbc_fail;
  355.     }
  356.  
  357.     if (statusParams.bCanCreateNow == NVFBC_FALSE) {
  358.         fprintf(stderr, "It is not possible to create a capture session "
  359.         "on this system.\n");
  360.         goto fbc_fail;
  361.     }
  362.  
  363.     printf("Screen size is %dx%d.\n",
  364.         statusParams.screenSize.w, statusParams.screenSize.h);
  365.  
  366.     if (frameSize.w > statusParams.screenSize.w ||
  367.         frameSize.h > statusParams.screenSize.h) {
  368.         fprintf(stderr, "Frames larger than %dx%d cannot be captured on this "
  369.         "system.\n", statusParams.screenSize.w, statusParams.screenSize.h);
  370.         goto fbc_fail;
  371.     }
  372.  
  373.     if (frameSize.w == 0) {
  374.         frameSize.w = statusParams.screenSize.w;
  375.     }
  376.  
  377.     if (frameSize.h == 0) {
  378.         frameSize.h = statusParams.screenSize.h;
  379.     }
  380.  
  381.     printf("FRAME_SIZE %d %d\n", frameSize.w, frameSize.h);
  382.  
  383.     memset(&createCaptureParams, 0, sizeof(createCaptureParams));
  384.     NVFBC_SIZE framey = {0, 0};
  385.  
  386.     createCaptureParams.dwVersion                   = NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER;
  387.     createCaptureParams.eCaptureType                = NVFBC_CAPTURE_TO_GL;
  388.     createCaptureParams.bWithCursor                 = NVFBC_FALSE;
  389.     createCaptureParams.frameSize                   = framey;
  390.     createCaptureParams.bRoundFrameSize             = NVFBC_TRUE;
  391.     createCaptureParams.eTrackingType               = NVFBC_TRACKING_DEFAULT;
  392.     createCaptureParams.bDisableAutoModesetRecovery = NVFBC_FALSE;
  393.  
  394.     fbcStatus = pFn.nvFBCCreateCaptureSession(fbcHandle, &createCaptureParams);
  395.     if (fbcStatus != NVFBC_SUCCESS) {
  396.         fprintf(stderr, "%s\n", pFn.nvFBCGetLastErrorStr(fbcHandle));
  397.         goto fbc_fail;
  398.     }
  399.  
  400.     /*
  401.      * Set up the capture session.
  402.      */
  403.     memset(&setupParams, 0, sizeof(setupParams));
  404.  
  405.     setupParams.dwVersion     = NVFBC_TOGL_SETUP_PARAMS_VER;
  406.     setupParams.eBufferFormat = NVFBC_BUFFER_FORMAT_NV12;
  407.  
  408.     fbcStatus = pFn.nvFBCToGLSetUp(fbcHandle, &setupParams);
  409.     if (fbcStatus != NVFBC_SUCCESS) {
  410.         fprintf(stderr, "%s\n", pFn.nvFBCGetLastErrorStr(fbcHandle));
  411.         goto fbc_fail;
  412.     }
  413.  
  414.     /*
  415.      * Start capturing and encoding frames.
  416.      */
  417.     printf("Capturing %dx%d frames...\n", frameSize.w, frameSize.h);
  418.     for (n = 0; n < nFrames; n++) {
  419.         NVFBC_TOGL_GRAB_FRAME_PARAMS grabParams;
  420.  
  421.         memset(&grabParams, 0, sizeof(grabParams));
  422.  
  423.         grabParams.dwVersion = NVFBC_TOGL_GRAB_FRAME_PARAMS_VER;
  424.     grabParams.dwFlags = NVFBC_TOGL_GRAB_FLAGS_NOWAIT;
  425.  
  426.         /*
  427.          * Capture a frame.
  428.          */
  429.         fbcStatus = pFn.nvFBCToGLGrabFrame(fbcHandle, &grabParams);
  430.         if (fbcStatus == NVFBC_ERR_MUST_RECREATE) {
  431.             printf("Capture session must be recreated!\n");
  432.             break;
  433.         } else if (fbcStatus != NVFBC_SUCCESS) {
  434.             fprintf(stderr, "%s\n", pFn.nvFBCGetLastErrorStr(fbcHandle));
  435.             break;
  436.         }
  437.     usleep(1000000/300);
  438.     }
  439.  
  440.     printf("Captured %d frames.\n", n);
  441.     printf("Destroying resources...\n");
  442.  
  443.  
  444. fbc_fail:
  445.     /*
  446.      * Destroy capture session.
  447.      */
  448.     memset(&destroyCaptureParams, 0, sizeof(destroyCaptureParams));
  449.  
  450.     destroyCaptureParams.dwVersion = NVFBC_DESTROY_CAPTURE_SESSION_PARAMS_VER;
  451.  
  452.     fbcStatus = pFn.nvFBCDestroyCaptureSession(fbcHandle, &destroyCaptureParams);
  453.     if (fbcStatus != NVFBC_SUCCESS) {
  454.         fprintf(stderr, "%s\n", pFn.nvFBCGetLastErrorStr(fbcHandle));
  455.     }
  456.  
  457.     /*
  458.      * Destroy session handle, tear down more resources.
  459.      */
  460.     memset(&destroyHandleParams, 0, sizeof(destroyHandleParams));
  461.  
  462.     destroyHandleParams.dwVersion = NVFBC_DESTROY_HANDLE_PARAMS_VER;
  463.  
  464.     fbcStatus = pFn.nvFBCDestroyHandle(fbcHandle, &destroyHandleParams);
  465.     if (fbcStatus != NVFBC_SUCCESS) {
  466.         fprintf(stderr, "%s\n", pFn.nvFBCGetLastErrorStr(fbcHandle));
  467.         return EXIT_FAILURE;
  468.     }
  469.  
  470.     return EXIT_SUCCESS;
  471. }
  472.  
  473. int main(int argc, char *argv[]) {
  474.     int count = 0;
  475.     while (True) {
  476.     printf("test %d\n", ++count);
  477.         test(argc, argv);
  478.     }
  479. }
  480.  
RAW Paste Data