• 在C++程序中给视频添加文字水印


    有时候,我们需要给视频添加文字或水印,用已有的工具当然最简单,但想在自己的应用中,如C++应用程序中来实现,如何实现呢?

    假设采用FFmpeg库,可通过C++二次开发调用实现。当然这个过程还是比较复杂的,需要有一定的多媒体编程能力并使用FFmpeg的多媒体处理功能。可按以下步骤:

    1、安装FFmpeg: 首先,确保你的系统上已经安装了FFmpeg。你可以从FFmpeg官方网站下载二进制文件,或者使用包管理器进行安装。

    2、包含FFmpeg头文件: 在你的C++程序中包含FFmpeg的头文件,以便你可以调用其功能。例

    1. extern "C" {
    2.  
    3.     #include
    4.     #include
    5. }
    6. }

    3、初始化FFmpeg: 在程序开始时初始化FFmpeg库:
     

    1. av_register_all();
    2. avformat_network_init();

    4、打开视频文件: 使用avformat_open_input打开视频文件,并调用avformat_find_stream_info以获取流信息。

    5、查找视频流: 遍历流以找到视频流。

    6、打开解码器: 创建一个视频解码器上下文,并打开解码器。

    7、创建水印: 创建水印的图像,通常是一个带有文字的图像。

    8、解码和渲染: 使用解码器解码每个视频帧,然后将水印叠加到帧上。

    9、播放视频: 将处理后的帧显示在屏幕上,或者保存为新的视频文件。

    10、释放资源: 在程序结束时释放FFmpeg资源,包括解码器、上下文等。

    以下是具体的例子,需要根据具体的需求修改。

    1. #include
    2. extern "C" {
    3. #include
    4. #include
    5. #include
    6. #include
    7. }
    8. }
    9. int main(int argc, char* argv[]) {
    10.  
    11.     av_register_all();
    12.  
    13.     avformat_network_init();
    14.     AVFormatContext* pFormatCtx = avformat_alloc_context();
    15.  
    16.     if (avformat_open_input(&pFormatCtx, "input.mp4", NULL, NULL) != 0) {
    17.  
    18.         std::cerr << "Failed to open input file." << std::endl;
    19.  
    20.         return -1;
    21.  
    22.     }
    23.     if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
    24.  
    25.         std::cerr << "Failed to find stream information." << std::endl;
    26.  
    27.         return -1;
    28.  
    29.     }
    30.     int videoStream = -1;
    31.  
    32.     for (int i = 0; i < pFormatCtx->nb_streams; i++) {
    33.  
    34.         if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
    35.  
    36.             videoStream = i;
    37.  
    38.             break;
    39.  
    40.         }
    41.  
    42.     }
    43.     if (videoStream == -1) {
    44.  
    45.         std::cerr << "No video stream found." << std::endl;
    46.  
    47.         return -1;
    48.  
    49.     }
    50.     AVCodecParameters* pCodecParams = pFormatCtx->streams[videoStream]->codecpar;
    51.  
    52.     AVCodec* pCodec = avcodec_find_decoder(pCodecParams->codec_id);
    53.  
    54.     AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
    55.  
    56.     avcodec_parameters_to_context(pCodecCtx, pCodecParams);
    57.  
    58.     avcodec_open2(pCodecCtx, pCodec, NULL);
    59.     AVPacket packet;
    60.  
    61.     AVFrame* pFrame = av_frame_alloc();
    62.  
    63.     AVFrame* pFrameRGB = av_frame_alloc();
    64.  
    65.     uint8_t* buffer;
    66.  
    67.     int numBytes;
    68.     numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 1);
    69.  
    70.     buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
    71.     av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 1);
    72.     struct SwsContext* sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);
    73.     while (av_read_frame(pFormatCtx, &packet) >= 0) {
    74.  
    75.         if (packet.stream_index == videoStream) {
    76.  
    77.             avcodec_send_packet(pCodecCtx, &packet);
    78.  
    79.             avcodec_receive_frame(pCodecCtx, pFrame);
    80.             // Add text watermark here
    81.             sws_scale(sws_ctx, (uint8_t const* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
    82.  
    83.             // Render the frame here or save it as a new video
    84.             av_packet_unref(&packet);
    85.  
    86.         }
    87.  
    88.     }
    89.     av_frame_free(&pFrame);
    90.  
    91.     av_frame_free(&pFrameRGB);
    92.  
    93.     avcodec_close(pCodecCtx);
    94.  
    95.     avformat_close_input(&pFormatCtx);
    96.     return 0;
    97. }
    98. }


    FFmpeg的使用和水印添加相对还是比较复杂的,需要不断的学习和实践,可以查阅FFmpeg的官方文档和示例来深入了解。在实际应用中,需要添加更多的错误处理和功能来满足需求。

  • 相关阅读:
    JAVA【注解】 自定义注解
    VMware 16开启虚拟机电脑就蓝屏W11解决方法
    设计模式之享元模式
    方块栈问题
    2022年12月STEMAC++中级组编程题
    Flutter 应用加速之本地缓存管理
    Dockerfile自定义镜像、CentOS安装DockerCompose及Docker镜像仓库
    Mac--WebStorm-前端环境配置(node.js+yarn)Taro框架使用
    JDBC批处理
    软件设计不是CRUD(4):耦合度的强弱(上)
  • 原文地址:https://blog.csdn.net/ygwelcome/article/details/136223958