Advertisement
Guest User

Untitled

a guest
Jan 13th, 2023
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.04 KB | Source Code | 0 0
  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <stdlib.h>
  4.  
  5. extern "C" {
  6. #include <libavutil/hwcontext.h>
  7. #include <libavcodec/avcodec.h>
  8. #include <libavformat/avformat.h>
  9. #include <libavutil/buffer.h>
  10. #include <libavfilter/buffersink.h>
  11. #include <libavfilter/buffersrc.h>
  12. #include <libavutil/opt.h>
  13. #include <libavutil/time.h>
  14. #include <libavcodec/packet.h>
  15. #include <libavfilter/avfilter.h>
  16. #include <libavutil/avutil.h>
  17. #include <libavutil/error.h>
  18. #include <libavutil/frame.h>
  19. #include <libavutil/log.h>
  20. #include <libavutil/pixfmt.h>
  21. #include <libavutil/rational.h>
  22. }
  23.  
  24. #include <string>
  25. #include <spdlog/spdlog.h>
  26.  
  27. static AVFormatContext *dFmtCtx = NULL;
  28. static AVFormatContext *eFmtCtx = NULL;
  29.  
  30. static AVBufferRef *hwDeviceCtx = NULL;
  31.  
  32. static AVCodecContext *dvCodecCtx = NULL;
  33. static AVCodecContext *evCodecCtx = NULL;
  34.  
  35. static AVCodecContext *daCodecCtx = NULL;
  36. static AVCodecContext *eaCodecCtx = NULL;
  37.  
  38. static const AVCodec *dvCodec = NULL;
  39. static const AVCodec *evCodec = NULL;
  40.  
  41. static const AVCodec *daCodec = NULL;
  42. static const AVCodec *eaCodec = NULL;
  43.  
  44. AVFilterContext *bufferSinkCtx = NULL;
  45. AVFilterContext *bufferSrcCtx = NULL;
  46. AVFilterGraph *filterGraph = NULL;
  47.  
  48. static AVStream *evStream = NULL;
  49.  
  50. AVFrame *frame = NULL;
  51. AVFrame *filterFrame = NULL;
  52.  
  53. int videoStream = -1;
  54. int audioStream = -1;
  55.  
  56. int eInitialized = 0;
  57. uint64_t frameCounter = av_gettime();
  58.  
  59. static const std::string av_make_error_string(int errnum)
  60. {
  61.     char errbuf[AV_ERROR_MAX_STRING_SIZE];
  62.     av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
  63.     return (std::string)errbuf;
  64. }
  65.  
  66. static void ffmpeg_log(void *avcl, int level, const char *fmt, va_list args)
  67. {
  68.     char logBuff[1024];
  69.     int prefix = 1;
  70.  
  71.     if (level == AV_LOG_ERROR || level == AV_LOG_PANIC || level == AV_LOG_FATAL) {
  72.         int rc = av_log_format_line2(avcl, level, fmt, args, logBuff, 1024, &prefix);
  73.         if (rc > 0) {
  74.             spdlog::error("FFMPEG internal error: {}", logBuff);
  75.         }
  76.     }
  77. }
  78.  
  79. static void initVideoDevEnc()
  80. {
  81.     dFmtCtx = NULL;
  82.     eFmtCtx = NULL;
  83.  
  84.     evCodecCtx = NULL;
  85.     dvCodecCtx = NULL;
  86.  
  87.     eaCodecCtx = NULL;
  88.     daCodecCtx = NULL;
  89.  
  90.     daCodec = NULL;
  91.     dvCodec = NULL;
  92.  
  93.     eaCodec = NULL;
  94.     evCodec = NULL;
  95.  
  96.     videoStream = -1;
  97.     audioStream = -1;
  98.  
  99. }
  100.  
  101. static enum AVPixelFormat get_cuda_format(AVCodecContext *ctx,
  102.                                           const enum AVPixelFormat *pixFmts)
  103. {
  104.     const enum AVPixelFormat *p;
  105.  
  106.     for (p = pixFmts; *p != AV_PIX_FMT_NONE; ++p) {
  107.         if (*p == AV_PIX_FMT_CUDA) {
  108.             return *p;
  109.         }
  110.     }
  111.  
  112.     fprintf(stderr, "Unable to decode this file using CUDA.\n");
  113.     return AV_PIX_FMT_NONE;
  114. }
  115.  
  116. static int init_filters(const char *filtersDescr) {
  117.  
  118.     int ret = 0;
  119.  
  120.     const AVFilter *bufferSrc  = avfilter_get_by_name("buffer");
  121.     const AVFilter *bufferSink = avfilter_get_by_name("buffersink");
  122.     AVFilterInOut *outputs = avfilter_inout_alloc();
  123.     AVFilterInOut *inputs  = avfilter_inout_alloc();
  124.     enum AVPixelFormat pixFmts[] = { AV_PIX_FMT_CUDA, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
  125.  
  126.     AVRational time_base = dFmtCtx->streams[videoStream]->time_base;
  127.  
  128.     filterGraph = avfilter_graph_alloc();
  129.  
  130.     if (!outputs || !inputs || !filterGraph) {
  131.         ret = AVERROR(ENOMEM);
  132.    
  133.         avfilter_inout_free(&inputs);
  134.         avfilter_inout_free(&outputs);
  135.  
  136.         return ret;
  137.     }
  138.  
  139.     spdlog::debug("Init filter with input format: {} {}", dvCodecCtx->pix_fmt, dvCodecCtx->sw_pix_fmt);
  140.  
  141.     char args[512];
  142.     snprintf(args, sizeof(args),
  143.             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
  144.             dvCodecCtx->width, dvCodecCtx->height, AV_PIX_FMT_CUDA,
  145.             time_base.num, time_base.den,
  146.             dvCodecCtx->sample_aspect_ratio.num, dvCodecCtx->sample_aspect_ratio.den);
  147.  
  148.     ret = avfilter_graph_create_filter(&bufferSrcCtx, bufferSrc, "in",
  149.                                        args, NULL, filterGraph);
  150.  
  151.     bufferSrcCtx->hw_device_ctx = av_buffer_ref(hwDeviceCtx);
  152.  
  153.     if (ret < 0) {
  154.         av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
  155.        
  156.         avfilter_inout_free(&inputs);
  157.         avfilter_inout_free(&outputs);
  158.  
  159.         return ret;
  160.     }
  161.  
  162.      /* buffer video sink: to terminate the filter chain. */
  163.     ret = avfilter_graph_create_filter(&bufferSinkCtx, bufferSink, "out",
  164.                                        NULL, NULL, filterGraph);
  165.     if (ret < 0) {
  166.         av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
  167.  
  168.         avfilter_inout_free(&inputs);
  169.         avfilter_inout_free(&outputs);
  170.  
  171.         return ret;
  172.     }
  173.  
  174.     bufferSinkCtx->hw_device_ctx = av_buffer_ref(hwDeviceCtx);
  175.  
  176.     ret = av_opt_set_int_list(bufferSinkCtx, "pix_fmts", pixFmts,
  177.                               AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
  178.     if (ret < 0) {
  179.         spdlog::error("Cannot set output pixel format");
  180.        
  181.         avfilter_inout_free(&inputs);
  182.         avfilter_inout_free(&outputs);
  183.  
  184.         return ret;
  185.     }
  186.  
  187.     outputs->name       = av_strdup("in");
  188.     outputs->filter_ctx = bufferSrcCtx;
  189.     outputs->pad_idx    = 0;
  190.     outputs->next       = NULL;
  191.  
  192.     inputs->name       = av_strdup("out");
  193.     inputs->filter_ctx = bufferSinkCtx;
  194.     inputs->pad_idx    = 0;
  195.     inputs->next       = NULL;
  196.  
  197.     if ((ret = avfilter_graph_parse_ptr(filterGraph, filtersDescr,
  198.                                     &inputs, &outputs, NULL)) < 0){
  199.         avfilter_inout_free(&inputs);
  200.         avfilter_inout_free(&outputs);
  201.  
  202.         return ret;
  203.     }
  204.  
  205.     if ((ret = avfilter_graph_config(filterGraph, NULL)) < 0) {
  206.  
  207.         avfilter_inout_free(&inputs);
  208.         avfilter_inout_free(&outputs);
  209.  
  210.         return ret;
  211.     }
  212.  
  213.     avfilter_inout_free(&inputs);
  214.     avfilter_inout_free(&outputs);
  215.  
  216.     return ret;
  217. }
  218.  
  219. static int open_input(const char *input, const int videoStreamRequest)
  220. {
  221.     int ret;
  222.  
  223.     if ((ret = avformat_open_input(&dFmtCtx, input, NULL, NULL)) < 0) {
  224.         fprintf(stderr, "Cannot open input '%s', Error code: %s\n", input, av_make_error_string(ret).c_str());
  225.         return ret;
  226.     }
  227.  
  228.     if ((ret = avformat_find_stream_info(dFmtCtx, NULL)) < 0) {
  229.         fprintf(stderr, "Cannot find input stream information. Error code: %s", av_make_error_string(ret).c_str());
  230.         return ret;
  231.     }
  232.  
  233.     spdlog::debug("Start find video stream");
  234.     spdlog::debug("Input programs: %d", dFmtCtx->nb_programs);
  235.  
  236.     for (int i = 0; i < dFmtCtx->nb_programs; ++i) {
  237.         AVProgram *program = dFmtCtx->programs[i];
  238.  
  239.         spdlog::debug("AVProgram program number: %d", program->program_num);
  240.  
  241.         for (int j = 0; j < program->nb_stream_indexes; ++j) {
  242.             spdlog::debug("-- AVProgram program {} Stream Index: {}", program->program_num, program->stream_index[j]);
  243.         }
  244.     }
  245.  
  246.     for (int i = 0; /*(audioStream == -1
  247.                     || videoStream == -1)
  248.                     &&*/ i < dFmtCtx->nb_streams; ++i) {
  249.         const AVStream *stream = dFmtCtx->streams[i];
  250.  
  251.         if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && stream->id == videoStreamRequest) {
  252.             spdlog::debug("Found Video stream with ID: {0:x}", stream->id);
  253.             spdlog::debug("-- Stream Index: {}", stream->index);
  254.             spdlog::debug("-- Side data count: {}", stream->nb_side_data);
  255.             spdlog::debug("-- Pixel format: {}", stream->codecpar->format);
  256.             spdlog::debug("-- Metadata count: {}", av_dict_count(stream->metadata));
  257.  
  258.             /* AVDictionaryEntry * av_dict_get */
  259.  
  260.             videoStream = i;
  261.         } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
  262.  
  263.             spdlog::debug("Found Audio stream with ID: {0:x}", stream->id);
  264.             spdlog::debug("-- Stream Index: {}", stream->index);
  265.             spdlog::debug("-- Side data count: {}", stream->nb_side_data);
  266.             spdlog::debug("-- Metadata count: {}", av_dict_count(stream->metadata));
  267.  
  268.             audioStream = i;
  269.         }
  270.     }
  271.  
  272.     fprintf(stdout, "Found Video stream index '%d' and audio stream index '%d'\n", videoStream, audioStream);
  273.  
  274.     if (videoStream == -1) {
  275.         fprintf(stderr, "Cannot find a video stream in the input.\n");
  276.         return -1;
  277.     }
  278.  
  279.     dvCodec = avcodec_find_decoder_by_name("h264");
  280.     if (dvCodec == NULL) {
  281.         fprintf(stderr, "Cannot find codec for decompress content.\n");
  282.  
  283.         return -1;
  284.     }
  285.  
  286.     printf("Found video stream\n");
  287.  
  288.     if (!(dvCodecCtx = avcodec_alloc_context3(dvCodec))) {
  289.         return AVERROR(ENOMEM);
  290.     }
  291.  
  292.     AVStream *video = dFmtCtx->streams[videoStream];
  293.  
  294.     spdlog::debug("Copy parameters to code context: {}", video->codecpar->codec_id);
  295.     spdlog::info("Codec to be used to decoding: {}", dvCodec->long_name);
  296.  
  297.     if (!(dvCodecCtx = avcodec_alloc_context3(dvCodec)))
  298.         return AVERROR(ENOMEM);
  299.  
  300.  
  301.     if ((ret = avcodec_parameters_to_context(dvCodecCtx, video->codecpar)) < 0) {
  302.         fprintf(stderr, "Parameters to context error. Error code: %s\n", av_make_error_string(ret).c_str());
  303.         return ret;
  304.     }
  305.  
  306.     spdlog::debug("Set Decoding context hardware device.");
  307.  
  308.     dvCodecCtx->hw_device_ctx = av_buffer_ref(hwDeviceCtx);
  309.     if (!dvCodecCtx->hw_device_ctx) {
  310.         fprintf(stderr, "A hardware device reference create failed.\n");
  311.         return AVERROR(ENOMEM);
  312.     }
  313.     dvCodecCtx->get_format = get_cuda_format;
  314.  
  315.     if ((ret = avcodec_open2(dvCodecCtx, dvCodec, NULL)) < 0) {
  316.         spdlog::error("Failed to open codec for decoding. Description: {}", av_make_error_string(ret));
  317.     }
  318.  
  319.     return ret;
  320. }
  321.  
  322. static int encode_write (AVPacket *packet, AVFrame *frame)
  323. {
  324.     int ret = 0;
  325.  
  326.     av_packet_unref(packet);
  327.  
  328.     if ((ret = avcodec_send_frame(evCodecCtx, frame)) < 0) {
  329.         fprintf(stderr, "Error during encoding. Error: %s\n", av_make_error_string(ret).c_str());
  330.  
  331.         return (ret == AVERROR_EOF) ? 0 : ret;
  332.     }
  333.  
  334.     while (1) {
  335.         ret = avcodec_receive_packet(evCodecCtx, packet);
  336.         if (ret) {
  337.             break;
  338.         }
  339.  
  340.         AVStream *encStream = eFmtCtx->streams[0];
  341.  
  342.         packet->pts = av_rescale_q(frameCounter, evCodecCtx->time_base, evStream->time_base);
  343.         packet->dts = AV_NOPTS_VALUE;
  344.         packet->stream_index = 0;
  345.  
  346.         frameCounter++;
  347.  
  348.         av_packet_rescale_ts(packet, dFmtCtx->streams[videoStream]->time_base, encStream->time_base);
  349.  
  350.         ret = av_write_frame(eFmtCtx, packet);
  351.         if (ret < 0) {
  352.             fprintf(stderr, "Error writing data to output. Error: %s\n", av_make_error_string(ret).c_str());
  353.             return -1;
  354.         }
  355.     }
  356.  
  357.     if (ret == AVERROR_EOF) {
  358.         return 0;
  359.     }
  360.  
  361.     ret = ((ret == AVERROR(EAGAIN)) ? 0 : -1);
  362.  
  363.     return ret;
  364. }
  365.  
  366. static int v_dec_enc (AVPacket *packet)
  367. {
  368.     int ret = avcodec_send_packet(dvCodecCtx, packet);
  369.     if (ret < 0) {
  370.         fprintf(stderr, "Can't send packet to decoder process: %s\n", av_make_error_string(ret).c_str());
  371.         return ret;
  372.     }
  373.  
  374.  
  375.     while (ret >= 0) {
  376.  
  377.         ret = avcodec_receive_frame(dvCodecCtx, frame);
  378.  
  379.         if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
  380.             av_frame_unref(frame);
  381.             av_frame_unref(filterFrame);
  382.  
  383.             return 0;
  384.         } else if (ret < 0) {
  385.             fprintf(stderr, "Error while decoding. Error code: %s\n", av_make_error_string(ret).c_str());
  386.             av_frame_unref(frame);
  387.             av_frame_unref(filterFrame);
  388.  
  389.             return ret;
  390.         }
  391.  
  392.          /* push the decoded frame into the filtergraph */
  393.         if (av_buffersrc_add_frame_flags(bufferSrcCtx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {
  394.             av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
  395.             break;
  396.         }
  397.  
  398.         if (!eInitialized) {
  399.             evCodecCtx->hw_frames_ctx = av_buffer_ref(dvCodecCtx->hw_frames_ctx);
  400.             if (!evCodecCtx->hw_frames_ctx) {
  401.                 fprintf(stderr, "Can't initialize hardware encoding on encoder context\n");
  402.                 ret = AVERROR(ENOMEM);
  403.  
  404.                 av_frame_unref(frame);
  405.                 av_frame_unref(filterFrame);
  406.  
  407.                 return ret;
  408.             }
  409.  
  410.             evCodecCtx->time_base = av_inv_q(dvCodecCtx->framerate);
  411.             evCodecCtx->pix_fmt = AV_PIX_FMT_CUDA;
  412.  
  413.             //evCodecCtx->width = dvCodecCtx->width;
  414.             //evCodecCtx->height = dvCodecCtx->height;
  415.            
  416.             evCodecCtx->width = 100;
  417.             evCodecCtx->height = 100;
  418.  
  419.  
  420.             if ((ret = avcodec_open2(evCodecCtx, evCodec, NULL)) < 0) {
  421.                 fprintf(stderr, "Failed to open encode codec. Error codes: %s\n", av_make_error_string(ret).c_str());
  422.  
  423.                 av_frame_unref(frame);
  424.                 av_frame_unref(filterFrame);
  425.  
  426.                 return ret;
  427.             }
  428.  
  429.             if (!(evStream = avformat_new_stream(eFmtCtx, evCodec))) {
  430.                 fprintf(stderr, "Failed to create video out stream\n");
  431.  
  432.                 av_frame_unref(frame);
  433.                 av_frame_unref(filterFrame);
  434.  
  435.                 return AVERROR(ENOMEM);
  436.             }
  437.  
  438.             evStream->time_base = evCodecCtx->time_base;
  439.             ret = avcodec_parameters_from_context(evStream->codecpar, evCodecCtx);
  440.             if (ret < 0) {
  441.                 fprintf(stderr, "Failed to copy the stream parameters. Error: %s\n", av_make_error_string(ret).c_str());
  442.  
  443.                 av_frame_unref(frame);
  444.                 av_frame_unref(filterFrame);
  445.  
  446.                 return ret;
  447.             }
  448.  
  449.             if ((ret = avformat_write_header(eFmtCtx, NULL)) < 0) {
  450.                 fprintf(stderr, "Error while writing stream header. Error: %s\n", av_make_error_string(ret).c_str());
  451.  
  452.                 av_frame_unref(frame);
  453.                 av_frame_unref(filterFrame);
  454.  
  455.                 return ret;
  456.             }
  457.  
  458.             eInitialized = 1;
  459.         }
  460.  
  461.         /* pull filtered frames from the filtergraph */
  462.         while (1) {
  463.             ret = av_buffersink_get_frame(bufferSinkCtx, filterFrame);
  464.  
  465.             if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
  466.                 ret = 0;
  467.                 break;
  468.             }
  469.  
  470.             if (ret < 0) {
  471.                 break;
  472.             }
  473.  
  474.             spdlog::debug("Frames format: {} {} {}", AV_PIX_FMT_CUDA, frame->format, filterFrame->format);
  475.  
  476.             if ((ret = encode_write(packet, frame)) < 0) {
  477.                 fprintf(stderr, "Error during encoding and write\n");
  478.             }
  479.  
  480.             av_frame_unref(filterFrame);
  481.         }
  482.  
  483.         av_frame_unref(frame);
  484.         av_frame_unref(filterFrame);
  485.  
  486.         if (ret < 0) {
  487.             return ret;
  488.         }
  489.     }
  490.  
  491.     return ret;
  492. }
  493.  
  494. int main(int argc, char **argv)
  495. {
  496.     spdlog::set_level(spdlog::level::debug);
  497.  
  498.     av_log_set_callback(ffmpeg_log);
  499.  
  500.     int rc = av_hwdevice_ctx_create(&hwDeviceCtx, AV_HWDEVICE_TYPE_CUDA, NULL, NULL, 0);
  501.     if (rc < 0) {
  502.         fprintf(stderr, "Failed to create a CUDA device. Error code: %s\n", av_make_error_string(rc).c_str());
  503.  
  504.         return EXIT_FAILURE;
  505.     }
  506.  
  507.     spdlog::debug("Hardware Context created");
  508.  
  509.  
  510.     if (!(frame = av_frame_alloc()) || !(filterFrame = av_frame_alloc())) {
  511.         return AVERROR(ENOMEM);
  512.     }
  513.  
  514.     AVPacket *packet = av_packet_alloc();
  515.     if (!packet) {
  516.         fprintf(stderr, "Can't create new packet for decoding\n");
  517.  
  518.         return EXIT_FAILURE;
  519.     }
  520.  
  521.     rc = open_input(argv[1], atoi(argv[2]));
  522.  
  523.      if ((rc = init_filters("hwupload_cuda,yadif_cuda,scale_cuda=w=100:h=100")) < 0 ) {
  524.         return EXIT_FAILURE;
  525.     }
  526.  
  527.     if (!(evCodec = avcodec_find_encoder_by_name("h264_nvenc"))) {
  528.         fprintf(stderr, "Could not find encoder h264_nvenc\n");
  529.  
  530.         return EXIT_FAILURE;
  531.     }
  532.  
  533.     if ((rc = avformat_alloc_output_context2(&eFmtCtx, NULL, "mpegts", NULL)) < 0) {
  534.         fprintf(stderr, "Failed to get output format. Error code: %s\n", av_make_error_string(rc).c_str());
  535.  
  536.         return EXIT_FAILURE;
  537.     }
  538.  
  539.     if (!(evCodecCtx = avcodec_alloc_context3(evCodec))) {
  540.         return EXIT_FAILURE;
  541.     }
  542.  
  543.     evCodecCtx->time_base = dvCodecCtx->time_base;
  544.     evCodecCtx->framerate = dvCodecCtx->framerate;
  545.  
  546.     fprintf(stdout, "Starting to decode-encode\n");
  547.  
  548.     int ret = avio_open(&eFmtCtx->pb, argv[3], AVIO_FLAG_WRITE);
  549.     if (ret < 0) {
  550.         fprintf(stderr, "Cannot open output stream '%s': Error code: %s\n", argv[3], av_make_error_string(ret).c_str());
  551.  
  552.         return EXIT_FAILURE;
  553.     }
  554.  
  555.     spdlog::info("Start decoding packets");
  556.  
  557.     /* read all packets and only transcoding video */
  558.     while (ret >= 0) {
  559.         if ((ret = av_read_frame(dFmtCtx, packet)) < 0) {
  560.             break;
  561.         }
  562.  
  563.         if (videoStream == packet->stream_index) {
  564.             ret = v_dec_enc(packet);
  565.         }
  566.  
  567.         av_packet_unref(packet);
  568.     }
  569.  
  570.     fprintf(stdout, "Finished to decode-encode\n");
  571.  
  572.     av_packet_unref(packet);
  573.  
  574.     av_frame_free(&frame);
  575.     av_frame_free(&filterFrame);
  576.  
  577.     return EXIT_SUCCESS;
  578. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement