前言:继上一篇推送网络流之后,最近又研究了一下读取网络流(顺便还有本地流)作为音视频源,此篇作为记录。
一、本地|网络视频源
1、初始化视频源
int VStreamCaptor::init(const std::string& url, const int fps)
{
int err = ERROR_CODE_OK;
if (m_inited) {
return err;
}
do {
m_deviceId = url;
err = initStream();
if (err != ERROR_CODE_OK) {
break;
}
m_fps = m_formatCtx->streams[m_streamIndex]->r_frame_rate.num / m_formatCtx->streams[m_streamIndex]->r_frame_rate.den;
m_rect = {
0, 0, m_decodeCtx->width, m_decodeCtx->height };
m_pixelFmt = m_decodeCtx->pix_fmt;
// 重要:获取相应视频流的时基,写入文件用
m_timebase = m_formatCtx->streams[m_streamIndex]->time_base;
m_inited = true;
} while (0);
if (err != ERROR_CODE_OK) {
LOGGER::Logger::log(LOGGER::LOG_TYPE_ERROR, "[%s] init vstream captor error: %s, last error: %lu",
__FUNCTION__, HCMDR_GET_ERROR_DESC(err), GetLastError());
cleanup();
}
return err;
}
其中最重要的initStream实现如下:
int VStreamCaptor::initStream()
{
int err = ERROR_CODE_OK;
do {
if (m_formatCtx == nullptr) {
m_formatCtx = avformat_alloc_context();
}
if (m_formatCtx == nullptr) {
err = ERROR_CODE_FFMPEG_ALLOC_CONTEXT_FAILED;
break;
}
if (m_decodeCtx == nullptr) {
m_decodeCtx = avcodec_alloc_context3(nullptr);
}
if (m_decodeCtx == nullptr) {
err = ERROR_CODE_FFMPEG_ALLOC_CONTEXT_FAILED;
break;
}
AVDictionary* options = nullptr;
if (m_deviceId.find("rtsp://") != std::string::npos) {
av_dict_set(&options, "rtsp_transport", "tcp", 0);
av_dict_set(&options, "stimeout", "8000000", 0);
}
int ret = avformat_open_input(&m_formatCtx, m_deviceId.c_str(), nullptr, &options);