视频解码
功能约束
视频解码功能的功能约束参见下表。
表 视频解码功能约束
约束项 |
属性 |
参数 |
---|---|---|
输入 |
分辨率 |
|
格式 |
|
|
缩放 |
支持2倍缩小和4倍缩小,缩小后的宽高需要2对齐 |
|
输入内存 |
输入内存是Client侧内存 |
|
输入方式 |
|
|
输出 |
输出格式 |
|
分辨率 |
|
|
输出内存 |
只能调用lynMalloc和lynFree进行视频解码输出的内存申请和释放 |
视频解码
用户可以从LynSDK提供的示例代码中查看完整样例,在示例代码中,调用各接口后都添加了异常判断和处理,以下是关键步骤代码示例,仅供参考,不可以直接拷贝编译。
// 预定义解码器输出buffer管理类
class DecRecvBufManager {
public:
int Init(int size, int num) {
void *newBuf;
int ret;
for (int i = 0; i < num; i++) {
ret = lynMalloc(&newBuf, size);
m_bufAll.push_back(newBuf);
m_freeBuf.push(newBuf);
}
}
void *GetNewBuf(uint32_t timeout = 300 * g_channelNum) {
std::unique_lock<std::mutex> lock(m_queueMux);
if (m_cvOutbufNum.wait_for(lock, std::chrono::seconds(timeout),
[this]{return this->m_freeBuf.size() > 0;}) != true) {
return nullptr;
}
void *buf = m_freeBuf.front();
m_freeBuf.pop();
return buf;
}
void FreeBuf(void *buf) {
std::unique_lock<std::mutex> lock(m_queueMux);
m_freeBuf.push(buf);
lock.unlock();
m_cvOutbufNum.notify_one();
}
void Destory() {
for (auto it : m_bufAll) {
lynFree(it);
}
m_bufAll.clear();
}
~DecRecvBufManager() {
Destory();
}
private:
std::queue<void *> m_freeBuf;
std::vector<void *> m_bufAll;
std::mutex m_queueMux;
std::condition_variable m_cvOutbufNum;
};
// 解码器输出信息
struct VdecBufInfo {
int id;
uint8_t *data;
uint32_t size;
uint32_t num;
DecRecvBufManager *manager;
};
// 解码器工作线程函数
int DecodeUrl(const char *url)
{
lynError_t ret = 0;
//runtime资源申请
lynContext_t context = nullptr;
ret = lynCreateContext(&context, 0);
//解封装初始化
lynDemuxHandle_t demuxHdl;
ret = lynDemuxOpen(&demuxHdl, url, nullptr);
lynCodecPara_t codecPara;
//获取解码参数
ret = lynDemuxGetCodecPara(demuxHdl, &codecPara);
int bufSize = codecPara.width * codecPara.height * 3 / 2;
lynPacket_t pkt;
int num = 0;
int totalSize = 0;
//打开解码器,配置解码参数
lynVdecAttr_t attr;
attr.codecId = codecPara.codecId;
attr.outputFmt = LYN_PIX_FMT_YUV420P;
lynVdecHandle_t vdecHdl;
ret = lynVdecOpen(&vdecHdl, &attr);
int vdecId = ((VdecHandle *)vdecHdl)->id;
//为视频解码创建发送Stream和接收Stream
lynStream_t sendStream = nullptr;
ret = lynCreateStream(&sendStream);
lynStream_t recvStream = nullptr;
ret = lynCreateStream(&recvStream);
//初始化解码器输出buffer
DecRecvBufManager recvBufManager;
recvBufManager.Init(bufSize, 5);
//循环送包过程
while (1) {
ret = lynDemuxReadPacket(demuxHdl, &pkt);
if (ret == EAGAIN) {
continue;
} else if (ret != 0) {
//解码完成,解封装去初始化,并发送eos标识
lynDemuxClose(demuxHdl);
/* set eos */
pkt.eos = true;
lynVdecSendPacketAsync(sendStream, vdecHdl, &pkt);
break;
}
num++;
totalSize += pkt.size;
// 在发送Stream中发送待解码数据
lynVdecSendPacketAsync(sendStream, vdecHdl, &pkt);
//同步等待并释放待解码数据内存(可选)
lynSynchronizeStream(sendStream);
lynDemuxFreePacket(&pkt);
//从解码器输出池中获取新的输出buffer并在接收Stream中接收解码之后的图像帧数据
lynFrame_t frame = {0};
frame.data = (uint8_t *)recvBufManager.GetNewBuf();
frame.size = bufSize;
lynVdecRecvFrameAsync(recvStream, vdecHdl, &frame);
VdecBufInfo *outBuf = (VdecBufInfo *)malloc(sizeof(VdecBufInfo));
outBuf->id = vdecId;
outBuf->data = frame.data;
outBuf->size = frame.size;
outBuf->num = num;
outBuf->manager = &recvBufManager;
//添加接收Stream异步回调函数,用户可自行选择在回调函数中进行结果保存、内存释放等逻辑
lynStreamAddAsyncCallback(recvStream, vdec_buffer_callback, outBuf);
}
//同步等待直至所有数据解码完成
lynSynchronizeStream(recvStream);
//关闭解码器
lynVdecClose(vdecHdl);
//runtime资源销毁
lynDestroyStream(sendStream);
lynDestroyStream(recvStream);
lynDestroyContext(context);
return 0;
}
//主函数调用流程
std::vector<std::thread> decThreads;
for (int i = 0; i < g_channelNum; i++) {
decThreads.push_back(std::thread(DecodeUrlThread, g_url.c_str()));
}
for (auto &it : decThreads) {
it.join();
}