avformat 用于解析容器和协议(protocol)。 avcodec 用于编码和解码基本流(您已经拥有的)。
Qt/C++音视频开发44-本地摄像头推流(支持分辨率/帧率等设置/实时性极高)_feiyangqingyun的博客-CSDN博客
- void FFmpegThread::initInputFormat()
- {
- //本地摄像头/桌面录屏
- if (videoType == VideoType_Camera) {
- #if defined(Q_OS_WIN)
- //ifmt = av_find_input_format("vfwcap");
- ifmt = av_find_input_format("dshow");
- #elif defined(Q_OS_LINUX)
- //可以打开cheese程序查看本地摄像头(如果是在虚拟机中需要设置usb选项3.1)
- //ifmt = av_find_input_format("v4l2");
- ifmt = av_find_input_format("video4linux2");
- #elif defined(Q_OS_MAC)
- ifmt = av_find_input_format("avfoundation");
- #endif
- } else if (videoType == VideoType_Desktop) {
- #if defined(Q_OS_WIN)
- ifmt = av_find_input_format("gdigrab");
- #elif defined(Q_OS_LINUX)
- ifmt = av_find_input_format("x11grab");
- #elif defined(Q_OS_MAC)
- ifmt = av_find_input_format("avfoundation");
- #endif
- }
- }
-
- bool FFmpegThread::initInput()
- {
- //实例化格式处理上下文
- formatCtx = avformat_alloc_context();
- //设置超时回调(有些不存在的地址或者网络不好的情况下要卡很久)
- formatCtx->interrupt_callback.callback = FFmpegHelper::avinterruptCallBackFun;
- formatCtx->interrupt_callback.opaque = this;
-
- //打开输入(通过标志位控制回调那边做超时判断)
- //其他地方调用 formatCtx->url formatCtx->filename 可以拿到设置的地址(两个变量值一样)
- tryOpen = true;
- QByteArray urlData = VideoHelper::getRightUrl(videoType, videoUrl).toUtf8();
- int result = avformat_open_input(&formatCtx, urlData.data(), ifmt, &options);
- tryOpen = false;
- if (result < 0) {
- debug("打开出错", "错误: " + FFmpegHelper::getError(result));
- return false;
- }
-
- //根据自己项目需要开启下面部分代码加快视频流打开速度
- //开启后由于值太小可能会出现部分视频流获取不到分辨率
- if (decodeType == DecodeType_Fastest && videoType == VideoType_Rtsp) {
- //接口内部读取的最大数据量(从源文件中读取的最大字节数)
- //默认值5000000导致这里卡很久最耗时(可以调小来加快打开速度)
- formatCtx->probesize = 50000;
- //从文件中读取的最大时长(单位为 AV_TIME_BASE units)
- formatCtx->max_analyze_duration = 5 * AV_TIME_BASE;
- //内部读取的数据包不放入缓冲区
- //formatCtx->flags |= AVFMT_FLAG_NOBUFFER;
- //设置解码错误验证过滤花屏
- //formatCtx->error_recognition |= AV_EF_EXPLODE;
- }
-
- //获取流信息
- result = avformat_find_stream_info(formatCtx, NULL);
- if (result < 0) {
- debug("找流失败", "错误: " + FFmpegHelper::getError(result));
- return false;
- }
-
- //解码格式
- formatName = formatCtx->iformat->name;
- //某些格式比如视频流不做音视频同步(响应速度快)
- if (formatName == "rtsp" || videoUrl.endsWith(".sdp")) {
- useSync = false;
- }
-
- //设置了最快速度则不启用音视频同步
- if (decodeType == DecodeType_Fastest) {
- useSync = false;
- }
-
- //有些格式不支持硬解码
- if (formatName.contains("rm") || formatName.contains("avi") || formatName.contains("webm")) {
- hardware = "none";
- }
-
- //本地摄像头设备解码出来的直接就是yuv显示不需要硬解码
- if (videoType == VideoType_Camera || videoType == VideoType_Desktop) {
- useSync = false;
- hardware = "none";
- }
-
- //过低版本不支持硬解码
- #if (FFMPEG_VERSION_MAJOR < 3)
- hardware = "none";
- #endif
-
- //获取文件时长(这里获取到的是秒)
- double length = (double)formatCtx->duration / AV_TIME_BASE;
- duration = length * 1000;
- this->checkVideoType();
-
- //有时候网络地址也可能是纯音频
- if (videoType == VideoType_FileHttp) {
- onlyAudio = VideoHelper::getOnlyAudio(videoUrl, formatName);
- }
-
- if (getIsFile()) {
- //文件必须要音视频同步
- useSync = true;
- //发送文件时长信号
- emit receiveDuration(duration > 0 ? duration : 0);
- }
-
- QString msg = QString("格式: %1 时长: %2 秒 加速: %3").arg(formatName).arg(duration / 1000).arg(hardware);
- debug("媒体信息", msg);
- return true;
- }
在线电子书