C++ 音视频流媒体浅谈

C++流媒体开发

今天就浅浅聊一下C++流媒体开发 

流媒体开发中最常见的是FFmpeg(编解码器)  业务逻辑主要是播放器了(如腾旭视频 爱奇艺等等)

FFmpeg是一个开源的音视频处理工具集,可以用于处理、转换和流媒体传输音视频文件。它包含了一系列的库和命令行工具,提供了强大的音视频编解码、格式转换、过滤器应用等功能。

以下是一些主要特点和功能:

  1. 格式支持广泛:FFmpeg支持几乎所有常见的音视频格式,包括但不限于MP4、AVI、MKV、MOV等。它能够对这些格式进行解码、编码和转换操作。

  2. 音视频编解码能力:FFmpeg支持多种音频编解码器(如AAC、MP3、FLAC)和视频编解码器(如H.264、H.265),可以实现音频和视频文件的压缩和解压缩操作。

  3. 视频流处理:FFmpeg可以处理各种视频流,包括网络摄像头实时流、屏幕捕捉流等。它能够进行录制、截取、转发等操作。

  4. 音频流处理:FFmpeg可以对音频流进行录制、混合、剪辑等操作。你可以从麦克风或其他输入设备获取音频,并将其发送到输出设备或保存为文件。

  5. 图像处理:除了音视频处理外,FFmpeg还提供了图像处理功能。你可以使用FFmpeg来调整图像大小,应用滤镜效果,进行图像转换等操作。

  6. 过滤器应用:FFmpeg内置了丰富的音视频过滤器,允许你对音视频进行处理和修改。你可以添加水印、调整亮度、对比度、色彩等参数,还可以实现视频剪裁、旋转和分割等操作。

FFmpeg是一个功能强大而灵活的工具,广泛应用于多媒体处理领域。它提供了简单易用的命令行界面和API接口,支持跨平台运行(Windows、Linux、macOS等),被众多开发者和专业用户所使用。

今天就聊一下音视频文件编码器(ffmpg)的转换吧(音视频的录制原理)

环境主要是Qt(Qt天然的支持跨平台)

编码主要流程

划分模块 

1.1 PCM 采集(麦克风+系统声音)+音频编码模块

1.2 Yun采集(摄像头+屏幕)+音视频编码模块 

   

解码主要流程:

将媒体数据解码 上面的过程逆行就可以了 这样就是一个完整播放器的模块

图中概念介绍:

1.时间戳  :时间戳通常指的是表示特定时间的数字或字符串

2.PCM:PCM(Pulse Code Modulation)是一种常用的数字音频编码方式,它将模拟声音信号转换为数字形式进行存储和传输。在PCM编码中,声音信号会被离散化成一系列采样点,并用固定的比特数来表示每个采样点的幅值。

3.Frame:在流媒体中,Frame(帧)是指一组连续的视频或音频数据。对于视频流来说,每个帧包含了一张完整的图像;对于音频流来说,每个帧包含了一段时间内的声音信号。

4.Packet:在计算机网络中,Packet(数据包)是将数据划分成小块进行传输的基本单位。它是网络通信中的信息载体,通过网络传输从源节点到目标节点。

5.Stream:音视频流

6.视频缓存:视频缓存是指在播放视频时,预先将部分视频数据存储在本地设备或服务器上,以提供更流畅的观看体验。

视频缓存 图像缓存类推

7.拉流;拉流是指从视频源服务器主动获取视频数据进行播放或处理的过程。在视频传输中,通常将视频源服务器称为推流端,而接收视频数据的设备称为拉流端

8.推流:推流是指将视频数据从源设备发送到视频服务器或云平台,以便其他用户可以通过网络观看或处理该视频流的过程。

9.YUV是一种常见的图像格式,它代表了图像的亮度(Y)和色度(U、V)信息。在视频处理和编码中经常使用YUV格式。

10.同步控制 :意思就是线程的同步 非异步编程

下面就介绍几个关于这些概念的代码实例

C++获取时间戳代码实例:

#include <iostream>
#include <chrono>

int main() {
    // 获取当前时间的时间戳(以秒为单位)
    auto now = std::chrono::system_clock::now();
    auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();

    // 输出时间戳
    std::cout << "Current timestamp: " << timestamp << " seconds" << std::endl;

    return 0;
}

C++PCM应用

#include <iostream>
#include <fstream>

int main() {
    // 打开 PCM 文件
    std::ifstream pcmFile("audio.pcm", std::ios::binary);
    if (!pcmFile) {
        std::cerr << "Failed to open PCM file." << std::endl;
        return 1;
    }

    // 读取 PCM 数据并进行处理
    const int bufferSize = 1024; // 缓冲区大小
    char buffer[bufferSize]; // 缓冲区

    while (!pcmFile.eof()) {
        pcmFile.read(buffer, bufferSize);
        // 在这里可以对 buffer 中的 PCM 数据进行处理,比如解码、编码、特征提取等
        // 这里只是简单地输出每个采样点的值(假设采样格式为16位有符号整数)
        for (int i = 0; i < pcmFile.gcount(); i += 2) {
            short sample = (buffer[i + 1] << 8) | buffer[i];
            std::cout << "Sample: " << sample << std::endl;
        }
    }

    // 关闭 PCM 文件
    pcmFile.close();

    return 0;
}

C++拉流代码应用

#include <opencv2/opencv.hpp>

int main() {
    // 视频流URL
    std::string stream_url = "your_stream_url_here";

    // 创建视频捕获对象
    cv::VideoCapture cap(stream_url);

    // 检查视频捕获对象是否成功打开视频流
    if (!cap.isOpened()) {
        std::cout << "无法打开视频流" << std::endl;
        return -1;
    }

    cv::Mat frame;

    while (true) {
        // 读取帧
        cap >> frame;

        // 检查帧是否成功读取
        if (frame.empty()) {
            std::cout << "无法读取帧" << std::endl;
            break;
        }

        // 显示帧图像
        cv::imshow("Video Stream", frame);

        // 按下 'q' 键退出循环
        if (cv::waitKey(1) == 'q') {
            break;
        }
    }

    // 释放资源和关闭窗口
    cap.release();
    cv::destroyAllWindows();

    return 0;
}

C++推流代码应用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

extern "C" {
  #include <libavformat/avformat.h>
  #include <libavutil/opt.h>
}

int main(int argc, char* argv[]) {
  // 输入参数
  const char* input_file = "input.mp4";
  const char* output_url = "rtmp://your-streaming-server.com/live/stream_key";

  // 初始化FFmpeg
  av_register_all();

  // 打开输入文件
  AVFormatContext* input_ctx = NULL;
  if (avformat_open_input(&input_ctx, input_file, NULL, NULL) != 0) {
    fprintf(stderr, "无法打开输入文件\n");
    return -1;
  }

  // 查找输入文件流信息
  if (avformat_find_stream_info(input_ctx, NULL) < 0) {
    fprintf(stderr, "无法获取流信息\n");
    avformat_close_input(&input_ctx);
    return -1;
  }

  // 创建输出上下文并设置输出格式
  AVFormatContext* output_ctx = NULL;
  
   if (avformat_alloc_output_context2(&output_ctx, NULL, "flv", output_url) == -1) {   
     fprintf(stderr, "无法创建输出上下文\n");
     avformat_close_input(&input_ctx);
     return -1;   
   }
   

 
   // 遍历输入文件中的所有流,并在输出上下文中添加相应的流
   for (unsigned int i = 0; i < input_ctx->nb_streams; ++i) {
      AVStream* in_stream = input_ctx->streams[i];
      AVCodec* codec = avcodec_find_decoder(in_stream->codecpar->codec_id);
      AVStream* out_stream = avformat_new_stream(output_ctx, codec);
      
      if (!out_stream) {
          fprintf(stderr, "无法创建输出流\n");
          avformat_close_input(&input_ctx);
          avformat_free_context(output_ctx);
          return -1;
       }
  
      // 复制流参数
      if (avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar) < 0) {
          fprintf(stderr, "无法复制流参数\n");
          avformat_close_input(&input_ctx);
          avformat_free_context(output_ctx);
         return -1;
     }
   }

   // 打开输出URL
    if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {   
        if (avio_open(&output_ctx->pb, output_url, AVIO_FLAG_WRITE) < 0) {    
           fprintf(stderr, "无法打开输出URL\n");
           avformat_close_input(&input_ctx);   
           avformat_free_context(output_ctx); 
           return -1;   
       } 
   }

   // 写入文件头部信息
   if (avformat_write_header(output_ctx, NULL) < 0) {
       fprintf(stderr, "无法写入文件头部信息\n");
       avio_close(output_ctx->pb); 
       avformat_close_input(&input_ctx);   
       avformat_free_context(output_ctx); 
       return -1;  
   }

   // 推送数据
   AVPacket packet;
  
   while (av_read_frame(input_ctx, &packet) >= 0) {
     AVStream* in_stream = input_ctx->streams[packet.stream_index];
     AVStream* out_stream = output_ctx->streams[packet.stream_index];

     // 调整帧的时间基
     av_packet_rescale_ts(&packet, in_stream->time_base, out_stream->time_base);
     packet.pos = -1;
     
     // 写入输出流
     if (av_interleaved_write_frame(output_ctx, &packet) < 0) {
         fprintf(stderr, "无法写入输出流\n");
         break;
      }

      av_packet_unref(&packet);
   }

   // 写入文件尾部信息
   av_write_trailer(output_ctx);

   // 关闭输入和输出上下文
    avio_close(output_ctx->pb);  
    avformat_close_input(&input_ctx);   
    avformat_free_context(output_ctx); 

    return 0;
}

好了 到这里对音视频的介绍就告一段落了 快过年了 祝大家新的一年里风调雨顺 事业有成

在这里小编有一个课程想介绍给大家:https://xxetb.xetslk.com/s/2PjJ3T

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/364368.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python-自动化篇-办公-文件-加解密

解说 要使⽤Python进⾏⽂件的加密和解密&#xff0c;可以使⽤第三⽅加密库&#xff0c;如cryptography或pycryptodome。 ⼀个基本的⽰例&#xff0c;演⽰如何使⽤cryptography库对⽂件进⾏加密和解密&#xff1a; 安装cryptography库&#xff1a; pip install cryptography⽂…

运行程序时出现“无效类”的解决方法

最近做开发时&#xff0c;遇到了一个奇怪的问题&#xff0c;打开的烧录软件突然出现了“无效类”的字样&#xff0c;以前打开却时正常的&#xff0c;真的是莫名其妙。 然后找了很久的解决办法&#xff0c;终于在某一天运行一个系统软件出现了同样的问题&#xff0c;有提示到WMI…

Kore.ai获10亿元融资,提供定制化类ChatGPT助手

1月31日&#xff0c;生成式AI和企业对话平台Kore.ai在官网宣布&#xff0c;获得1.5 亿美元&#xff08;约10.7亿元&#xff09;融资。本次由FTV Capital 领投&#xff0c;英伟达等跟投。 Kore.ai主要提供银行、医疗、零售、营销、人力资源等多种领域的&#xff0c;定制化类Cha…

【Qt学习笔记】(二)信号和槽

信号和槽 1 信号和槽概述2 信号和槽的使用3 可视化生成槽函数4 自定义信号和槽5 带参数的信号和槽6 信号与槽的连接方式7 信号与槽的断开8 使用 Lambda 表达式来定义槽函数 1 信号和槽概述 在Qt中&#xff0c;用户和控件的每次交互过程称为一个事件。比如"用户点击按钮&q…

在Android Studio中配置OpenCV

在Android Studio中配置OpenCV 1 下载OpenCV2 导入OpenCV模块3 修改配置4 增加依赖5 拷贝libopencv_java.so6 Activity中加入代码1 下载OpenCV 下载OpenCV的Android包并解压。 2 导入OpenCV模块 在Android应用中,导入OpenCV模块。 导入目录时选择Opencv Android中的sdk目…

杠杆交易在伦敦金市场的优势与风险

伦敦金作为黄金市场的灯塔&#xff0c;每天吸引着全球投资者的目光。伦敦金的特殊地位使得以它为基准的杠杆交易成为众多投资者追逐的目标。在这篇文章中&#xff0c;我们将深入探讨伦敦金杠杆交易的奥秘&#xff0c;带你揭开这一盛宴的神秘面纱。 伦敦金杠杆交易的核心在于通过…

bs4模块

bs4模块与案例 使用指南 bs4&#xff0c;全称BeautifulSoup 4&#xff0c;是Python中一个强大的网页解析库&#xff0c;它可以帮助我们方便地从网页中提取数据。bs4将复杂HTML文档转换成树形结构&#xff0c;每个节点都是Python对象&#xff0c;所有对象可以归纳为4种&#xf…

vue动态修改侧边菜单栏宽度

1.添加可修改宽度的dom元素 <div style"background: #f5f7fa;padding: 20px 10px;"><label>菜单宽度 </label><el-input v-model"sideWidth" placeholder"请输入宽度值" style"width: 100px"/> px<el-but…

PMP认证是如何评估项目管理能力的?

当提及项目管理能力时&#xff0c;PMP认证是广泛接受的评估标准。作为项目管理领域的权威认证&#xff0c;PMP评估了申请人在项目管理方面的专业能力和实践经验。那么&#xff0c;PMP认证如何评估项目管理能力呢&#xff1f;本文将揭示PMP认证的评估体系和流程。 PMP认证的评估…

Notion 开源替代品:兼容 Miro 绘图 | 开源日报 No.162

toeverything/AFFiNE Stars: 25.6k License: NOASSERTION AFFiNE 是下一代知识库&#xff0c;将规划、排序和创建集于一身。它是一个注重隐私、开源、可定制且即插即用的替代方案&#xff0c;可以与 Notion 和 Miro 相媲美。主要功能和优势包括&#xff1a; 超融合&#xff1…

Android系统-应用程序中的View框架

源码分析基于Android 7 应用程序中的View框架如图所示 1. View和ViewRoot 单单从名称看很容易让人产生误解&#xff0c;因为ViewRoot并不属于View树的一分子。源码上ViewRoot和View对象也没有继承关系。更准确说ViewRoot理解为View输的管理者&#xff0c;ViewRoot有一个mView成…

apk反编译修改教程系列---修改apk的默认颜色 布局颜色 手机电脑同步演示【十】

往期教程&#xff1a; apk反编译修改教程系列-----修改apk应用名称 任意修改名称 签名【一】 apk反编译修改教程系列-----任意修改apk版本号 版本名 防止自动更新【二】 apk反编译修改教程系列-----修改apk中的图片 任意更换apk桌面图片【三】 apk反编译修改教程系列---简单…

【Tomcat与网络11】如何自己实现一个简单的HTTP服务器

在前面我们尝试解释Tomcat的理论&#xff0c;但是呢&#xff0c;很多时候那些复杂的架构和设计会让我们眼花缭乱&#xff0c;以至于忽略了最进本的问题——服务器到底是什么&#xff1f;今天我们就用尽量简单的代码实现一个简易的HTTP服务器。 HTTP启动之后要持续监听&#xf…

ele-h5项目使用vue3+vite开发:第二节、search 搜索框组件开发

如何设计一个组件 需求分析 布局 content left-iconbodyinput-controlright-iconaction 功能 使用 defineEmits 定义组件的事件 在组件的script setup 里如何定义事件 使用defineEmits&#xff08;&#xff09;定义先声明事件接口 <script setup lang"ts"> int…

某赛通电子文档安全管理系统 UploadFileToCatalog SQL注入漏洞复现

0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…

睿尔曼超轻量仿人机械臂——外置按钮一键启停程序配置

在睿尔曼超轻量仿人机械臂—外置按钮盒使用说明一文中&#xff0c;介绍了外置按钮盒的安装及使用。它能够使机械臂的使用变得更加编辑&#xff0c;仅需按钮即可完成运动程序的启停等控制&#xff0c;而无需进入示教界面操作。 在示教界面中&#xff0c;我们可以完成运动程序的…

UserWarning: Glyph 39640 missing from current font问题

是因为不支持中文字体导致的&#xff0c;设置为一个支持中文的字体就行了。 另外&#xff0c;上面的改动会引起负号显示为方块&#xff0c;需要额外再加一条设置。 在中文系统上 import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # 设置为一个支持…

xlsx xlsx-style坑记录

1 安装 npm install xlsx --savenpm install xlsx-style --save Umi运行会报错 自己代码 import XLSX from "xlsx"; import XLSXStyle from "xlsx-style";const data [["demo1","demo2","demo3","demo4","…

计算机设计大赛 深度学习 python opencv 火焰检测识别 火灾检测

文章目录 0 前言1 基于YOLO的火焰检测与识别2 课题背景3 卷积神经网络3.1 卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV54.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 数据集准备5.1 数…

CSS3的新盒子,选择器等

新增的选择器&#xff1a; 属性选择器&#xff1a; 结构伪类选择选器&#xff1a; nth较为重要&#xff1a;但公式中的字母必须是n 区别&#xff1a; nth-child&#xff1a; 认为父类下的都是儿子&#xff0c;此时就需要有对应的需要&#xff0c;如下&#xff0c;此时即使排1&…
最新文章