最近在做安卓下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这方面的内容再更新一下吧。。。