以下文章用于记录个人学习使用,如有出入请帮忙指正,不胜感激!
承接上编博文分析:https://blog.youkuaiyun.com/zhfabel/article/details/119184807
上篇文章分析到:
void SourceStreamFlow::ReadThreadRun() {
prctl(PR_SET_NAME, this->tag.c_str());
source_start_cond_mtx->lock();
if (waite_down_flow) {
if (down_flow_num == 0 && IsEnable()) {
source_start_cond_mtx->wait();
}
}
source_start_cond_mtx->unlock();
while (loop) {
if (stream->Eof()) {
// TODO: tell that I reach eof
SetDisable();
break;
}
auto buffer = stream->Read();
SendInput(buffer, 0);
}
}
SourceStreamFlow::ReadThreadRun()中的SendInput(buffer, 0)函数,主要与flow类相关,本篇主要以auto buffer = stream->Read();为主线进一步分析stream的类概论。
手册Rockchip_Instructions_Linux_MediaServer_CN 中定义:Stream表示FLow使用的处理方法。
先看下,stream对象的定义处:$(SDK)\external\rkmedia\src\flow\source_stream_flow.cc
class SourceStreamFlow : public Flow {
public:
SourceStreamFlow(const char *param);
virtual ~SourceStreamFlow();
static const char *GetFlowName() { return "source_stream"; }
virtual int Control(unsigned long int request, ...) final {
if (!stream)
return -1;
va_list vl;
va_start(vl, request);
void *arg = va_arg(vl, void *);
va_end(vl);
return stream->IoCtrl(request, arg);
}
private:
void ReadThreadRun();
bool loop;
std::thread *read_thread;
std::shared_ptr<Stream> stream;
std::string tag;
};
std::shared_ptr<Stream> stream这句指引我们到:$(SDK)\external\rkmedia\include\easymedia\stream.h,stream类接口定义不大,直接贴出
// interface
class _API Stream {
public:
static StreamOperation c_operations;
Stream() : readable(false), writeable(false), seekable(false) {}
virtual ~Stream() = default;
virtual size_t Read(void *ptr, size_t size, size_t nmemb) = 0;
virtual size_t Write(const void *ptr, size_t size, size_t nmemb) = 0;
// whence: SEEK_SET, SEEK_CUR, SEEK_END
virtual int Seek(int64_t offset, int whence) = 0;
virtual long Tell() = 0;
virtual int NewStream(std::string new_path _UNUSED) { return -1; };
virtual size_t WriteAndClose(const void *ptr _UNUSED,
size_t size _UNUSED, size_t nmemb _UNUSED) { return -1; };
virtual int ReName(std::string old_path _UNUSED,
std::string new_path _UNUSED) { return -1; };
virtual bool Readable() { return readable; }
virtual bool Writeable() { return writeable; }
virtual bool Seekable() { return seekable; }
void SetReadable(bool able) { readable = able; }
void SetWriteable(bool able) { writeable = able; }
void SetSeekable(bool able) { seekable = able; }
virtual bool Eof() { return false; }
// No need size input. For some device, such as V4L2, always return specific
// buffer
virtual std::shared_ptr<MediaBuffer> Read() { return nullptr; }
virtual bool Write(std::shared_ptr<MediaBuffer>) { return false; }
// The IoCtrl must be called in the same thread of Read()/Write()
virtual int IoCtrl(unsigned long int request _UNUSED, ...) { return -1; }
virtual int SubIoCtrl(unsigned long int request _UNUSED, void *arg, int size = 0) {
SubRequest subreq = {request, size, arg};
return IoCtrl(S_SUB_REQUEST, &subreq);
}
// read data as image by ImageInfo
bool ReadImage(void *ptr, const ImageInfo &info);
protected:
virtual int Open() = 0;
virtual int Close() = 0;
friend int local_close(void *stream);
private:
bool readable;
bool writeable;
bool seekable;
DECLARE_PART_FINAL_EXPOSE_PRODUCT(Stream)
};
从仅3个成员变量看出,定义了stream的可读,可写,可seek。其中除以下4个函数外其他都是虚函数,在实际继承类中定义具体的功能。
void SetReadable(bool able) { readable = able; }
void SetWriteable(bool able) { writeable = able; }
void SetSeekable(bool able) { seekable = able; }
// read data as image by ImageInfo
bool ReadImage(void *ptr, const ImageInfo &info);
SourceStreamFlow::SourceStreamFlow(const char *param)的构造函数中有如下stream是实例化:stream = REFLECTOR(Stream)::Create<Stream>(stream_name, stream_param.c_str());
以第一篇分析的实例化一个对象指针。
代码位置:$(SDK\external\rkmedia\include\easymedia\reflector.h
以Read()函数为主线,跟踪分析下继承Stream基类的具体实现:class V4L2Stream的继承类分析,位置:$(SDK)\external\rkmedia\src\stream\camera\v4l2_stream.h;其中Read仍是虚函数,未具体实现,class V4L2Stream进一步被class V4L2CaptureStream,所以分析 V4L2CaptureStream::Read()函数。
virtual size_t Read(void *ptr _UNUSED, size_t size _UNUSED,
size_t nmemb _UNUSED) final {
return 0;
}
std::shared_ptr<MediaBuffer> V4L2CaptureStream::Read() {
const char *dev = device.c_str();
if (!started && v4l2_ctx->SetStarted(true))
started = true;
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = capture_type;
buf.memory = memory_type;
int ret = v4l2_ctx->IoCtrl(VIDIOC_DQBUF, &buf);
if (ret < 0) {
LOG("%s, ioctl(VIDIOC_DQBUF): %m\n", dev);
return nullptr;
}
struct timeval buf_ts = buf.timestamp;
MediaBuffer &mb = buffer_vec[buf.index];
std::shared_ptr<MediaBuffer> ret_buf;
if (buf.bytesused > 0) {
if (pix_fmt != PIX_FMT_NONE) {
ImageInfo info{pix_fmt, width, height, width, height};
ret_buf = std::make_shared<AutoQBUFImageBuffer>(mb, info, v4l2_ctx, buf);
} else {
ret_buf = std::make_shared<AutoQBUFMediaBuffer>(mb, v4l2_ctx, buf);
}
}
if (ret_buf) {
assert(ret_buf->GetFD() == mb.GetFD());
if (buf.memory == V4L2_MEMORY_DMABUF) {
assert(ret_buf->GetFD() == buf.m.fd);
}
ret_buf->SetAtomicTimeVal(buf_ts);
ret_buf->SetTimeVal(buf_ts);
ret_buf->SetValidSize(buf.bytesused);
} else {
if (v4l2_ctx->IoCtrl(VIDIOC_QBUF, &buf) < 0)
LOG("%s, index=%d, ioctl(VIDIOC_QBUF): %m\n", dev, buf.index);
}
return ret_buf;
}
总体看函数返回值为std::shared_ptr<MediaBuffer>,应该是读到的camera数据流,返回数据流的缓存块,使用v4l2的架构接口(如下代码段可以看出)。
if (ret_buf) {
assert(ret_buf->GetFD() == mb.GetFD());
if (buf.memory == V4L2_MEMORY_DMABUF) {
assert(ret_buf->GetFD() == buf.m.fd);
}
ret_buf->SetAtomicTimeVal(buf_ts);
ret_buf->SetTimeVal(buf_ts);
ret_buf->SetValidSize(buf.bytesused);
} else {
if (v4l2_ctx->IoCtrl(VIDIOC_QBUF, &buf) < 0)
LOG("%s, index=%d, ioctl(VIDIOC_QBUF): %m\n", dev, buf.index);
}
综上分析,最终read就是调用了通过linux v4l2架构或则Media Controller
架构获取到camera的数据流缓存