<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
一開始用ffmpeg做的是視訊流的解析,後面增加了本地視訊檔的支援,到後面發現ffmpeg也是支援本地攝像頭裝置的,只要是原則上打通的比如win系統上相機程式、linux上茄子程式可以正常開啟就表示打通,整個解碼顯示過程完全一樣,就是開啟的時候要傳入裝置資訊,而且引數那邊可以指定解析度和影格率等,本地攝像機一般會支援多個解析度,使用者需要哪種解析度都可以指定該解析度進行採集。
這裡要說的一個小插曲就是在linux上測試這個功能的時候,發現編譯期間就失敗了,這就奇怪了,後面發現是靜態庫的原因,為了偷懶,一開始編譯的ffmpeg靜態庫,當換成動態庫的方式以後,一步跑通不要太完美,完美使用,所以如果有載入本地攝像頭裝置的需求的時候,儘量用動態庫的方式。一鼓作氣將程式碼移植到嵌入式linux板子上,完美,居然也可以,而且實時性挺好,可能內建了部分快取的原因,比自己用v4l2的方式更流暢一些。
由於本地攝像頭裝置採集回來的資料預設的yuv422格式,顯示資料那邊預設是yuv420格式,當然改成繪製yuv422也是可以的,但是有需要更改繪製程式碼,而且儲存那邊也要做特殊處理,所以考慮再三決定從源頭做轉換,用sws_scale轉換各種格式都非常方便,本來ffmpeg採集這邊就需要將非yuv420格式轉到yuv420格式。
國內站點:https://gitee.com/feiyangqingyun
國際站點:https://github.com/feiyangqingyun
體驗地址:https://pan.baidu.com/s/1YOVD8nkoOSYwX9KgSauLeQ 提取碼:kcgz 檔名:bin_video_demo/bin_linux_video。
void CameraThreadFFmpeg::initCamera() { //https://blog.csdn.net/weixin_37921201/article/details/120357826 //命令列開啟 ffplay -f dshow -i video="USB Video Device" -s 1280x720 -framerate 30 //啟動計時 timer.restart(); //引數字典 AVDictionary *options = NULL; //設定解析度 QString size = QString("%1x%2").arg(videoWidth).arg(videoHeight); av_dict_set(&options, "video_size", size.toUtf8().constData(), 0); //設定影格率 if (frameRate > 0) { av_dict_set(&options, "framerate", QString::number(frameRate).toUtf8().constData(), 0); } //設定輸入格式(前提是要對應裝置對應平臺支援) //av_dict_set(&options, "input_format", "mjpeg", 0); //設定影象格式(有些裝置設定了格式後影格率上不去) //av_dict_set(&options, "pixel_format", "yuyv422", 0); //列印裝置列表 //FFmpegHelper::showDevice(); //列印裝置引數 //FFmpegHelper::showOption(cameraName); //範例化格式處理上下文 formatCtx = avformat_alloc_context(); AVInputFormatx *ifmt = NULL; QByteArray url = cameraName.toUtf8(); #if defined(Q_OS_WIN) //ifmt = av_find_input_format("vfwcap"); ifmt = av_find_input_format("dshow"); url = QString("video=%1").arg(cameraName).toUtf8(); #elif defined(Q_OS_LINUX) //ifmt = av_find_input_format("v4l2"); ifmt = av_find_input_format("video4linux2"); #elif defined(Q_OS_MAC) ifmt = av_find_input_format("avfoundation"); #endif int result = avformat_open_input(&formatCtx, url.data(), ifmt, &options); av_dict_free(&options); if (result < 0) { debug("開啟地址", "錯誤: 開啟出錯 " + FFmpegHelper::getError(result)); return; } //獲取流資訊 result = avformat_find_stream_info(formatCtx, NULL); if (result < 0) { debug("開啟地址", "錯誤: 找流失敗 " + FFmpegHelper::getError(result)); return; } //獲取最佳流索引 AVCodecx *videoCodec; videoIndex = av_find_best_stream(formatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); if (videoIndex < 0) { debug("開啟地址", "錯誤: 未找到視訊流"); return; } //獲取視訊流 AVStream *videoStream = formatCtx->streams[videoIndex]; //查詢視訊解碼器(如果上面av_find_best_stream第五個引數傳了則這裡不需要) AVCodecID codecID = FFmpegHelper::getCodecID(videoStream); videoCodec = avcodec_find_decoder(codecID); //videoCodec = avcodec_find_decoder_by_name("h264"); if (!videoCodec) { debug("開啟地址", "錯誤: 查詢視訊解碼器失敗"); return; } //建立視訊流解碼器上下文 videoCodecCtx = avcodec_alloc_context3(videoCodec); if (!videoCodecCtx) { debug("開啟地址", "錯誤: 建立視訊解碼器上下文失敗"); return; } result = FFmpegHelper::copyContext(videoCodecCtx, videoStream, false); if (result < 0) { debug("開啟地址", "錯誤: 設定視訊解碼器引數失敗"); return; } //設定解碼器引數 videoCodecCtx->flags |= AV_CODEC_FLAG_LOW_DELAY; videoCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; videoCodecCtx->flags2 |= AV_CODEC_FLAG2_FAST; //開啟視訊解碼器 result = avcodec_open2(videoCodecCtx, videoCodec, NULL); if (result < 0) { debug("開啟地址", "錯誤: 開啟視訊解碼器失敗 " + FFmpegHelper::getError(result)); return; } //獲取實際解析度大小 FFmpegHelper::getResolution(videoStream, videoWidth, videoHeight); //如果沒有獲取到寬高則返回 if (videoWidth <= 0 || videoHeight <= 0) { debug("開啟地址", "錯誤: 獲取寬度高度失敗"); return; } //獲取最終真實的影格率 frameRate = av_q2d(videoStream->r_frame_rate); QString msg = QString("索引: %1 解碼: %2 影格率: %3 寬高: %4x%5").arg(videoIndex).arg(videoCodec->name).arg(frameRate).arg(videoWidth).arg(videoHeight); debug("視訊資訊", msg); openCamera(); } bool CameraThreadFFmpeg::openCamera() { //分配記憶體 packet = FFmpegHelper::creatPacket(NULL); videoFrame = av_frame_alloc(); yuvFrame = av_frame_alloc(); imageFrame = av_frame_alloc(); //設定屬性以便該幀物件正常 yuvFrame->format = AV_PIX_FMT_YUV420P; yuvFrame->width = videoWidth; yuvFrame->height = videoHeight; //定義及獲取畫素格式 AVPixelFormat srcFormat = AV_PIX_FMT_YUYV422; //通過解碼器獲取解碼格式 srcFormat = videoCodecCtx->pix_fmt; //各種轉換速度比對 https://www.cnblogs.com/xumaojun/p/8541634.html int flags = SWS_FAST_BILINEAR; //分配視訊幀資料(轉yuv420) int yuvSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 1); yuvData = (quint8 *)av_malloc(yuvSize * sizeof(quint8)); av_image_fill_arrays(yuvFrame->data, yuvFrame->linesize, yuvData, AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 1); //視訊影象轉換(轉yuv420) yuvSwsCtx = sws_getContext(videoWidth, videoHeight, srcFormat, videoWidth, videoHeight, AV_PIX_FMT_YUV420P, flags, NULL, NULL, NULL); //分配視訊幀資料(轉rgb) int imageSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, videoWidth, videoHeight, 1); imageData = (quint8 *)av_malloc(imageSize * sizeof(quint8)); av_image_fill_arrays(imageFrame->data, imageFrame->linesize, imageData, AV_PIX_FMT_RGB24, videoWidth, videoHeight, 1); //視訊影象轉換(轉rgb) imageSwsCtx = sws_getContext(videoWidth, videoHeight, AV_PIX_FMT_YUV420P, videoWidth, videoHeight, AV_PIX_FMT_RGB24, flags, NULL, NULL, NULL); //列印媒體資訊 //av_dump_format(formatCtx, 0, 0, 0); QString msg = QString("源頭: %1 目標: %2").arg(srcFormat).arg(videoMode == VideoMode_Painter ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_YUV420P); debug("格式資訊", msg); //初始化音訊播放 this->initAudioPlayer(); //初始化濾鏡 this->initFilter(); int time = timer.elapsed(); debug("開啟成功", QString("用時: %1 毫秒").arg(time)); emit receivePlayStart(time); emit recorderStateChanged(RecorderState_Stopped, fileName); isOk = true; return isOk; }
以上就是Qt音視訊開發之利用ffmpeg實現解碼本地攝像頭的詳細內容,更多關於Qt ffmpeg解碼本地攝像頭的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45