音视频的Buffer处理

news2024/11/27 0:36:03

最近在做安卓下UVC的一个案子。正好之前搞过ST方案的开机广告,这个也是我少数最后没搞成功的项目。当时也有点客观原因,当时ST要退出机顶盒市场,所以一切的支持都停了,当时啃他家播放器几十万行的代码,而且几乎没有文档,真的是非常痛苦。后面虽然功能是搞出来了,但是不稳定,持续几次后就会crash。

还记得当时最后到底层ST是用的滑动窗口缓存,双指针,一个写指针和一个读指针,当时我做了一个管道往缓存中注数据。估计还是没有完全吃透,某些细节处理有问题。正好现在又做到类似项目,所以简单总结总结相关要点。主要就是共享内存,滑动窗口,双缓冲,环形缓冲这些内容。

下面是一个简单的具有读写指针的循环缓冲区。

#include <iostream>
#include <vector>
#include <stdexcept>

template<typename T>
class MediaQueue {
public:
    explicit MediaQueue(size_t size)
        : buffer(size), readPtr(0), writePtr(0), count(0), maxSize(size) {}

    // 添加一个元素到队列中
    void enqueue(const T& item) {
        if (isFull()) {
            throw std::overflow_error("Queue is full");
        }
        buffer[writePtr] = item;
        writePtr = (writePtr + 1) % maxSize;
        ++count;
    }

    // 从队列中读取一个元素
    T dequeue() {
        if (isEmpty()) {
            throw std::underflow_error("Queue is empty");
        }
        T item = buffer[readPtr];
        readPtr = (readPtr + 1) % maxSize;
        --count;
        return item;
    }

    // 检查队列是否为空
    bool isEmpty() const {
        return count == 0;
    }

    // 检查队列是否已满
    bool isFull() const {
        return count == maxSize;
    }

    // 获取队列中的元素数量
    size_t size() const {
        return count;
    }

    // 获取队列的最大容量
    size_t capacity() const {
        return maxSize;
    }

private:
    std::vector<T> buffer;
    size_t readPtr;
    size_t writePtr;
    size_t count;
    size_t maxSize;
};

还有一种叫做乒乓buffer

就是两个buffer,一个读一个写,写完之后交换。

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <cstring> // For memcpy
#include <chrono> // For sleep

class PingPongBuffer {
public:
    PingPongBuffer(size_t bufferSize)
        : bufferSize(bufferSize), readBufferIndex(0), writeBufferIndex(1), buffers(2, std::vector<char>(bufferSize)) {}

    // 写入数据到当前写缓冲区
    void write(const char* data, size_t size) {
        std::unique_lock<std::mutex> lock(mutex);
        while (writeBufferFull) {
            condVar.wait(lock);
        }
        if (size > bufferSize) {
            throw std::overflow_error("Data size exceeds buffer capacity");
        }
        std::memcpy(buffers[writeBufferIndex].data(), data, size);
        writeBufferFull = true;
        readBufferEmpty = false;
        swapBuffers();
        condVar.notify_all();
    }

    // 从当前读缓冲区读取数据
    void read(char* data, size_t size) {
        std::unique_lock<std::mutex> lock(mutex);
        while (readBufferEmpty) {
            condVar.wait(lock);
        }
        if (size > bufferSize) {
            throw std::underflow_error("Data size exceeds buffer capacity");
        }
        std::memcpy(data, buffers[readBufferIndex].data(), size);
        readBufferEmpty = true;
        writeBufferFull = false;
        condVar.notify_all();
    }

private:
    void swapBuffers() {
        std::swap(readBufferIndex, writeBufferIndex);
    }

    size_t bufferSize;
    int readBufferIndex;
    int writeBufferIndex;
    std::vector<std::vector<char>> buffers;
    bool readBufferEmpty = true;
    bool writeBufferFull = false;
    std::mutex mutex;
    std::condition_variable condVar;
};

void producer(PingPongBuffer& buffer) {
    const char* messages[] = {"Message 1", "Message 2", "Message 3"};
    for (const char* message : messages) {
        std::this_thread::sleep_for(std::chrono::seconds(1)); // Simulate work
        buffer.write(message, std::strlen(message) + 1);
        std::cout << "Produced: " << message << std::endl;
    }
}

void consumer(PingPongBuffer& buffer) {
    char data[1024];
    for (int i = 0; i < 3; ++i) {
        buffer.read(data, 1024);
        std::cout << "Consumed: " << data << std::endl;
    }
}

int main() {
    size_t bufferSize = 1024;
    PingPongBuffer buffer(bufferSize);

    std::thread producerThread(producer, std::ref(buffer));
    std::thread consumerThread(consumer, std::ref(buffer));

    producerThread.join();
    consumerThread.join();

    return 0;
}

空了有时间看看V4L2和ffmpeg这方面的内容再更新一下吧。。。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件操作<C语言>

导言 平时我们在写程序时&#xff0c;在运行时申请内存空间&#xff0c;运行完时内存空间被收回&#xff0c;如果想要持久化的保存&#xff0c;我们就可以使用文件&#xff0c;所以下文将要介绍一些在程序中完成一些文件操作。 目录 导言 文件流 文件指针 文件的打开与关闭 …

Android 开发必备知识点及面试题汇总(Android+Java+算法+性能优化+四大组件……

**虚引用&#xff1a;**顾名思义&#xff0c;就是形同虚设&#xff0c;如果一个对象仅持有虚引用&#xff0c;那么它相当于没有引用&#xff0c;在任何时候都可能被垃圾回收器回收。 7.介绍垃圾回收机制 **标记回收法&#xff1a;**遍历对象图并且记录可到达的对象&#xff0c…

WPS没保存关闭了怎么恢复数据?4个方法(更新版)

想象一下&#xff0c;你正在用WPS奋笔疾书&#xff0c;灵感如泉水般涌出&#xff0c;突然间&#xff0c;电脑却跟你开了个玩笑——啪地一下&#xff0c;文档未保存就关闭了&#xff01;是不是感觉像是被泼了一盆冷水&#xff0c;所有的热情瞬间熄灭&#xff1f;别急&#xff0c…

为 Android 应用打造精良的 Chrome OS 使用体验

override fun onKeyUp(code: Int, ev: KeyEvent?): Boolean { return when (code) { KeyEvent.KEYCODE_J -> { // Do something here true } else -> super.onKeyUp(code, ev) // 重要&#xff01;&#xff01; } } 注意我们标出 “重要” 的那一行代码。这行代…

20240623 每日AI必读资讯

&#x1f916;原生鸿蒙AI浓度要爆表了&#xff01; - 一年一度华为开发者大会上&#xff0c;余承东首次揭秘“鸿蒙原生智能”Harmony Intelligence&#xff01; - 华为小艺进化成系统级智能体。 - 一句话实现跨多个应用的规划和任务执行&#xff1b;在第三方APP上随意处理文…

Unity的渲染管线

渲染管线 概念 Unity的渲染管线是在图形学渲染管线的基础上&#xff0c;加上了高度可配置可扩展的框架&#xff0c;允许开发者自定义渲染流程。 渲染管线&#xff08;渲染流水线&#xff09;概述&#xff1a;将数据分阶段的变为屏幕图像的过程。 数据指的是模型、光源和摄像…

C++ | Leetcode C++题解之第174题地下城游戏

题目&#xff1a; 题解&#xff1a; class Solution { public:int calculateMinimumHP(vector<vector<int>>& dungeon) {int n dungeon.size(), m dungeon[0].size();vector<vector<int>> dp(n 1, vector<int>(m 1, INT_MAX));dp[n][m …

【从0实现React18】 (二) JSX 的转换 jsx到底是什么?React是如何把jsx转换为ReactElement?

react项目结构 React(宿主环境的公用方法)React-reconciler(协调器的实现&#xff0c;宿主环境无关)各种宿主环境的包shared(公用辅助方法&#xff0c;宿主环境无关) 当前实现的JSX转换属于 react****包 初始化react包 先创建react package并初始化 更新package.json文件&a…

Redis源码学习:quicklist的设计与实现

为什么需要quicklist 假设你已经知道了ziplist的缺陷&#xff1a; 虽然节省空间&#xff0c;但是申请内存必须是连续的&#xff0c;如果内存占用比较多&#xff0c;申请效率低要存储大量数据&#xff0c;超过了ziplist的最佳上限后&#xff0c;性能有影响 借鉴分片思想&…

仓颉编程语言入门

华为在 2024 年 6 月 21 日的华为开发者大会上&#xff0c;华为终端 BG 软件部总裁龚体正式官宣了华为自研仓颉编程语言&#xff0c;并发布了 HarmonyOS NEXT 仓颉语言开发者预览版。 仓颉编程语言文件后缀名为 .cj, 以下是第一个入门代码输出&#xff1a;你好&#xff0c;仓颉…

理解 什么是 滚动更新,蓝绿部署,灰度发布 以及它们的区别

滚动更新&#xff0c;蓝绿部署&#xff0c;灰度发布 这3种 现代化的 发布模式相信很多人都听过&#xff0c; 但是并不是都能正确理解他们的作用和区别 滚动更新 Rolling Update 所谓滚动更新是for 那些多实例的service的。 假如1个 service 有n 个instance, 更新时并不是n 个…

xss.haozi.me靶场通关参考

url&#xff1a;https://xss.haozi.me/ 文章目录 0x000x010x020x030x040x050x060x070x080x090x0A0x0B0x0C00xD00xE00xF0x100x110x12 0x00 先看js代码&#xff0c;第一关给你热热手&#xff0c;没给你加过 payload&#xff1a; <script>alert(1)</script>0x01 这…

移动端 UI 风格,诠释精致

移动端 UI 风格&#xff0c;诠释精致

文华财经wh7关于mancd和KDJ预警指标公式源码

一、零轴下金叉和零轴上死叉的预警 MA5:MA(C,5); MA10:MA(C,10); DIFF:EMA(CLOSE,12) - EMA(CLOSE,26); DEA:EMA(DIFF,9); MACD:2*(DIFF-DEA); CROSS(MA5,MA10)&&MAX(DIFF,DEA)<0,NOTICE(零轴下金叉); CROSSDOWN(MA5,MA10)&&MIN(DIFF,DEA)>0,NOTI…

华为---理解OSPF Route-ID(五)

9.5 理解OSPF Route-ID 9.5.1 原理概述 一些动态路由协议要求使用Router-ID作为路由器的身份标示&#xff0c;如果在启动这些路由协议时没有指定Router-ID,则默认使用路由器全局下的路由管理Router-ID。 Router-ID选举规则为&#xff0c;如果通过Router-ID命令配置了Router-…

46、基于自组织映射神经网络的鸢尾花聚类(matlab)

1、自组织映射神经网络的鸢尾花聚类的原理及流程 自组织映射神经网络&#xff08;Self-Organizing Map, SOM&#xff09;是一种用于聚类和数据可视化的人工神经网络模型。在鸢尾花聚类中&#xff0c;SOM 可以用来将鸢尾花数据集分成不同的类别&#xff0c;同时保留数据间的拓扑…

centos7系统上安装MySQL8.4图文教程

本章教程&#xff0c;主要记录如何在CentOS7系统上安装MySQL8.4的详细步骤。 一、查看当前系统版本 cat /etc/centos-release二、安装步骤 1、创建mysql目录 cd /usr/local && mkdir mysql && cd mysql2、安装rpm包 yum install https://repo.mysql.com//m…

[FreeRTOS 基础知识] 互斥访问与回环队列 概念

文章目录 为什么需要互斥访问&#xff1f;使用队列实现互斥访问休眠和唤醒机制环形缓冲区 为什么需要互斥访问&#xff1f; 在裸机中&#xff0c;假设有两个函数&#xff08;func_A, func_B&#xff09;都要修改a的值&#xff08;a&#xff09;&#xff0c;那么将a定义为全局变…

Django数据驾驶舱

Django数据驾驶舱 1.项目介绍2.项目结构3.库表结构3.1 appcsdn的models3.2 appssq的models3.3 appweather的models3.4 appweibo的models 4.功能展示5.解决问题5.1 路由配置5.2 后端数据与前端echarts展示5.3 长图表丝滑滚动条 6.遗留问题7.资源分享 1.项目介绍 这里介绍本人最…

STM32读写备份寄存器和实时时钟

文章目录 1. 硬件电路 2. RTC操作注意事项 操作步骤 3. 代码实现 3.1 读写备份寄存器 3.1.1 main.c 3.2 实时时钟 3.2.1 MyRTC.c 3.2.2 MyRTC.h 3.2.3 main.c 1. 硬件电路 对于BKP备份寄存器和RTC实时时钟的详细解析可以看下面这篇文章&#xff1a; STM32单片机BKP备…