<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
和音訊儲存類似,視訊的儲存也對應三種格式,視訊最原始的資料是yuv(音訊對應pcm),視訊壓縮後的資料是h264(音訊對應aac),由於很多播放器或者早期的播放器不支援直接播放h264檔案,所以需要用編碼器編碼成mp4格式,這塊就需要用到ffmpeg裡面一整套的編碼流程,對yuv資料進行編碼成MP4格式儲存。
在經過對各種視訊檔或者視訊流儲存的過程中,發現rtsp這類的視訊流可以直接編碼打包儲存,不需要經過 avcodec_send_frame avcodec_receive_packet 這兩個步驟對每個包編碼,這樣可以極大的降低CPU佔用,猜測可能是rtsp視訊流收到的封包packet就已經是標準的h264裸流帶了各種pps啥的。所以視訊的監控領域如果要同時儲存16路32路視訊,採用這個策略是最穩妥的,相當於一直寫檔案。很多人會覺得編碼流程繁瑣,其實只要靜下心來,挨個測試,把流程搞懂,基本上都是水到渠成的事情。包括之前遇到的儲存的檔案滑鼠右鍵屬性中看不到解析度等引數資訊,原來是呼叫寫入檔案頭 avformat_write_header 寫入的時機不對,一定要在開啟開啟視訊編碼器 avcodec_open2 以及開啟輸出檔案 avio_open 以後再寫入。
編碼儲存的大致流程:
國內站點:https://gitee.com/feiyangqingyun
國際站點:https://github.com/feiyangqingyun
體驗地址:https://pan.baidu.com/s/1bNGaPFZc7UovQI57UIQSbw 提取碼:xk9a 檔名:bin_video_demo/bin_linux_video。
bool FFmpegSave::initVideoH264() { //查詢視訊編碼器(如果源頭是H265則採用HEVC作為編碼器) AVCodecID codecID = FFmpegHelper::getCodecID(videoStreamIn); if (codecID == AV_CODEC_ID_HEVC) { videoCodec = avcodec_find_encoder(AV_CODEC_ID_HEVC); } else { videoCodec = avcodec_find_encoder(AV_CODEC_ID_H264); } if (!videoCodec) { debug("編碼失敗", QString("錯誤: 查詢視訊編碼器失敗")); return false; } //建立視訊編碼器上下文 videoCodecCtx = avcodec_alloc_context3(videoCodec); if (!videoCodecCtx) { debug("編碼失敗", QString("錯誤: 建立視訊編碼器上下文失敗")); return false; } //為了相容低版本的編譯器推薦選擇第一種方式 #if 1 //放大係數是為了小數位能夠正確放大到整型 int ratio = 10000; videoCodecCtx->time_base.num = 1 * ratio; videoCodecCtx->time_base.den = frameRate * ratio; videoCodecCtx->framerate.num = frameRate * ratio; videoCodecCtx->framerate.den = 1 * ratio; #elif 0 videoCodecCtx->time_base = {1, frameRate}; videoCodecCtx->framerate = {frameRate, 1}; #else videoCodecCtx->time_base = videoStreamIn->codec->time_base; videoCodecCtx->framerate = videoStreamIn->codec->framerate; #endif #if 0 videoCodecCtx->qmin = 10; videoCodecCtx->qmax = 51; videoCodecCtx->me_range = 16; videoCodecCtx->max_qdiff = 4; videoCodecCtx->qcompress = 0.6; #endif //初始化視訊編碼器引數(如果要檔案體積小一些畫質差一些可以調整位元速率) //引數說明 https://blog.csdn.net/qq_40179458/article/details/110449653 videoCodecCtx->bit_rate = FFmpegHelper::getBitRate(videoWidth, videoHeight); videoCodecCtx->width = videoWidth; videoCodecCtx->height = videoHeight; videoCodecCtx->gop_size = 25; videoCodecCtx->max_b_frames = 3; videoCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; videoCodecCtx->level = 50; videoCodecCtx->profile = FF_PROFILE_H264_MAIN; //加上下面這個才能在檔案屬性中看到解析度等資訊 https://www.cnblogs.com/lidabo/p/15754031.html if (saveVideoType == SaveVideoType_Mp4) { videoCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } //載入預設 https://blog.csdn.net/JineD/article/details/125304570 if (videoCodecCtx->codec_id == AV_CODEC_ID_H264) { av_opt_set(videoCodecCtx->priv_data, "preset", "slow", 0); //設定零延遲(本地攝像頭視訊流儲存如果不設定則播放的時候會越來越模糊) av_opt_set(videoCodecCtx->priv_data, "tune", "zerolatency", 0); } else if (videoCodecCtx->codec_id == AV_CODEC_ID_HEVC) { av_opt_set(videoCodecCtx->priv_data, "x265-params", "qp=20", 0); av_opt_set(videoCodecCtx->priv_data, "preset", "ultrafast", 0); av_opt_set(videoCodecCtx->priv_data, "tune", "zero-latency", 0); } //開啟視訊編碼器 int result = avcodec_open2(videoCodecCtx, videoCodec, NULL); if (result < 0) { debug("開啟編碼", QString("錯誤: 開啟視訊編碼器失敗 %1").arg(FFmpegHelper::getError(result))); return false; } videoPacket = FFmpegHelper::creatPacket(NULL); return true; } bool FFmpegSave::initVideoMp4() { //必須先設定過輸入視訊流 if (!videoStreamIn || fileName.isEmpty()) { return false; } //有部分視訊引數不正確儲存不了 http://tv.netxt.cc:1998/live/y.flv if (videoStreamIn->time_base.num == 0) { return false; } QByteArray fileData = fileName.toUtf8(); const char *filename = fileData.data(); //開闢一個格式上下文用來處理視訊流輸出 int result = avformat_alloc_output_context2(&formatCtx, NULL, "mp4", filename); if (result < 0) { debug("建立格式", QString("錯誤: %1").arg(FFmpegHelper::getError(result))); return false; } //建立視訊流用來輸出視訊資料到檔案 videoStreamOut = avformat_new_stream(formatCtx, NULL); result = FFmpegHelper::copyContext(videoCodecCtx, videoStreamOut, true); if (result < 0) { debug("建立視訊", QString("錯誤: %1").arg(FFmpegHelper::getError(result))); goto end; } //開啟輸出檔案 result = avio_open(&formatCtx->pb, filename, AVIO_FLAG_WRITE); if (result < 0) { debug("開啟輸出", QString("錯誤: %1").arg(FFmpegHelper::getError(result))); goto end; } //寫入檔案開始符 result = avformat_write_header(formatCtx, NULL); if (result < 0) { debug("寫入失敗", QString("錯誤: %1").arg(FFmpegHelper::getError(result))); goto end; } return true; end: //關閉釋放並清理檔案 this->close(); this->deleteFile(fileName); return false; } void FFmpegSave::writePacket(AVPacket *packet) { packetCount++; if (saveVideoType == SaveVideoType_H264) { file.write((char *)packet->data, packet->size); } else if (saveVideoType == SaveVideoType_Mp4) { AVRational timeBaseIn = videoStreamIn->time_base; AVRational timeBaseOut = videoStreamOut->time_base; //沒有下面這段判斷在遇到不連續的幀的時候就會錯位(相當於每次重新計算時間基準保證時間正確) //不連續幀的情況有暫停錄製以及切換播放進度導致中間有些幀不需要錄製 double fps = frameRate;//av_q2d(videoStreamIn->r_frame_rate); double duration = AV_TIME_BASE / fps; packet->pts = (packetCount * duration) / (av_q2d(timeBaseIn) * AV_TIME_BASE); packet->dts = packet->pts; packet->duration = duration / (av_q2d(timeBaseIn) * AV_TIME_BASE); //重新調整時間基準 packet->pts = av_rescale_q_rnd(packet->pts, timeBaseIn, timeBaseOut, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); packet->dts = packet->pts; //packet->dts = av_rescale_q_rnd(packet->dts, timeBaseIn, timeBaseOut, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); packet->duration = av_rescale_q(packet->duration, timeBaseIn, timeBaseOut); packet->pos = -1; //寫入一幀資料 int result = av_interleaved_write_frame(formatCtx, packet); if (result < 0) { debug("寫入失敗", QString("錯誤: %1").arg(FFmpegHelper::getError(result))); } } av_packet_unref(packet); }
到此這篇關於Qt音視訊開發之視訊檔儲存功能的實現的文章就介紹到這了,更多相關Qt視訊檔儲存內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援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