.. _video_decoding: 视频解码 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _functional_constraints_of_video_decoding: 功能约束 """"""""""""""""""""""""""""""""""""""""""""""""""""" 视频解码功能的功能约束参见下表。 .. _table_11_video_decoding_constraints: 表 视频解码功能约束 """"""""""""""""""""""""""""""""""""""""""""""""""""" +----------+-----------+------------------------------------------------------------+ | 约束项 | 属性 | 参数 | +==========+===========+============================================================+ | 输入 | 分辨率 | - 最大:4096×4096 | | | | - 最小:16×16 | | | | - 宽高2对齐 | | +-----------+------------------------------------------------------------+ | | 格式 | - H.264 Baseline/Main/High/High 10 Profile | | | | - H.265 Main/Main 10 Profile | | +-----------+------------------------------------------------------------+ | | 缩放 | 支持2倍缩小和4倍缩小,缩小后的宽高需要2对齐 | | +-----------+------------------------------------------------------------+ | | 输入内存 | 输入内存是Client侧内存 | | +-----------+------------------------------------------------------------+ | | 输入方式 | - 只支持按帧输入的码流进行视频解码 | | | | - 只支持逐行扫描方式编码出来的码流解码 | +----------+-----------+------------------------------------------------------------+ | 输出 | 输出格式 | - YUV420SP NV12 | | | | - YUV420SP NV21 | | | | - YUV420P YU12 | | | | - NV12 10bit | | +-----------+------------------------------------------------------------+ | | 分辨率 | - 最大:4096×4096 | | | | - 最小:16×16 | | | | - 宽高2对齐 | | +-----------+------------------------------------------------------------+ | | 输出内存 | 只能调用lynMalloc和lynFree进行视频解码输出的内存申请和释放 | +----------+-----------+------------------------------------------------------------+ .. _video_decoding_process: 视频解码 """"""""""""""""""""""""""""""""""""""""""""""""""""" 用户可以从LynSDK提供的示例代码中查看完整样例,在示例代码中,调用各接口后都添加了异常判断和处理,以下是关键步骤代码示例,仅供参考,不可以直接拷贝编译。 .. code-block:: c++ // 预定义解码器输出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 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 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 m_freeBuf; std::vector 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 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(); }