FFMPEG 解碼過程初步學習

1. 視頻文件解碼過程

解碼過程

在這里插入圖片描述

步驟如下:

  1. 視頻文件(封裝格式,MP4/FLV/AVI 等)獲取視頻格式信息等
  2. 解復用為Stream 流, 準備解碼用的Codec
  3. 將Stream 流 使用解碼器解為Raw 格式針

1.1 音視頻格式填充:

int ret = avformat_open_input(&format_ctx, filename, nullptr, nullptr);  // 打開輸入文件并將格式上下文賦給 format_ctx
// 填充stream 信息
if (avformat_find_stream_info(format_ctx, NULL) < 0) {std::cout << "no stream in files : " << std::endl;return -1;
}// find the video stream information
ret = av_find_best_stream(format_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (ret < 0) {fprintf(stderr, "Cannot find a video stream in the input file\n");return -1;
}
video_stream_index = ret;
video_stream = format_ctx->streams[video_stream_index];ret = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
if (ret < 0) {std::cout<< "no audio stream " << ret << std::endl;
} else {audio_stream_index = ret;audio_stream = format_ctx->streams[audio_stream_index];
}

1.2 準備解碼用的codec

const AVCodec * video_codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
if (video_codec == nullptr) {std::cout << "we not found the code: " << video_decoder->id << std::endl;
} else {std::cout << "we found the video codec: " << video_codec->name << std::endl;
}
const AVCodec * audio_codec = avcodec_find_decoder(audio_stream->codecpar->codec_id);
if (audio_codec == nullptr) {std::cout << "we not found the code: " << audio_decoder->id << std::endl;
} else {std::cout << "we found the audio codec: " << audio_codec->name << std::endl;
}// codec context for decoder 
AVCodecContext* video_dec_context = avcodec_alloc_context3(video_codec);
if (!video_dec_context) {std::cout << "video dec context alloc failed" << std::endl;
}
if ((ret = avcodec_parameters_to_context(video_dec_context, video_stream->codecpar)) < 0) {std::cerr << "codec copy failed" << std::endl;
}
std::cout<< "video format width: " << video_dec_context->width << std::endl;
std::cout<< "video format height: " << video_dec_context->height << std::endl;
std::cout << "video pixel format: " << video_dec_context->pix_fmt << std::endl;
video_width = video_dec_context->width;
video_height = video_dec_context->height;
video_fmt = video_dec_context->pix_fmt;
// open codec
ret = avcodec_open2(video_dec_context, video_codec, NULL);
if (ret < 0) {std::cerr << "video codec open failed" << std::endl;
}

Audio 的流程和video 的流程相近:
通過stream 信息->AVCodec->AVCodecContext , 再通過AVCodecContext 打開解碼器(avcodec_open2)

1.3 解碼過程:

在打開解碼器后,創建AVPacket AVFrame
AVPacket 是解碼前的包, AVFrame 是解碼后的幀

AVPacket *packet;
packet = av_packet_alloc();AVFrame* frame = av_frame_alloc();while(1) {// 從里面獲取一個packetret1 = av_read_frame(format_ctx, packet);if (ret1 < 0) {break;} else {/*if (packet->stream_index == video_stream_index) {std::cout << "Video: pts: " << packet->pts << " dts: " << packet->dts <<" duration: " << packet->duration << std::endl;} else {if (packet->stream_index != -1 && audio_stream_index == packet->stream_index) {std::cout << "Audio: pts: " << packet->pts << " dts: " << packet->dts <<" duration: " << packet->duration << std::endl;}}*/if (packet->stream_index == video_stream_index) {int result = decode_packet(video_dec_context, packet);if (result == 0) {//video_frame_count++;}} else {decode_packet(audio_dec_context, packet);av_frame_unref(frame);}}av_packet_unref(packet);}
// 解包過程
static int decode_packet(AVCodecContext *dec, const AVPacket *pkt)
{int ret = 0;// submit the packet to the decoderret = avcodec_send_packet(dec, pkt);if (ret < 0) {fprintf(stderr, "Error submitting a packet for decoding (%d)\n", ret);return ret;}// get all the available frames from the decoderwhile (ret >= 0) {ret = avcodec_receive_frame(dec, frame);if (ret < 0) {// those two return values are special and mean there is no output// frame available, but there were no errors during decodingif (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))return 0;// fprintf(stderr, "Error during decoding (%s)\n", av_err2str(ret));std::cerr << "Error during decoding " << ret << std::endl;return ret;}// // write the frame data to output fileif (dec->codec->type == AVMEDIA_TYPE_VIDEO) {static int video_frame_count = 0;/* copy decoded frame to destination buffer:* this is required since rawvideo expects non aligned data */// std::cout << "frame size: " << frame->linesize << std::endl;av_image_copy2(video_dst_data, video_dst_linesize,frame->data, frame->linesize,video_fmt, video_width, video_height);/* write to rawvideo file */size_t size =  fwrite(video_dst_data[0], 1, video_dst_bufsize, video_dst_file);if (size == 0) {std::cerr << "write failed" << std::endl;return -1;} else {video_frame_count++;std::cout << " write to video frame count: " << video_frame_count << std::endl;}}//ret = output_video_frame(frame);// else//     ret = output_audio_frame(frame);av_frame_unref(frame);}return ret;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/15199.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/15199.shtml
英文地址,請注明出處:http://en.pswp.cn/web/15199.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

找不到msvcr110.dll無法繼續執行代碼的原因分析及解決方法

在計算機使用過程中&#xff0c;我們經常會遇到一些錯誤提示&#xff0c;其中之一就是找不到msvcr110.dll文件。這個錯誤通常發生在運行某些程序或游戲時&#xff0c;系統無法找到所需的動態鏈接庫文件。為了解決這個問題&#xff0c;下面我將介紹5種常見的解決方法。 一&#…

Vue3實現上傳照片以及回顯

Vue3實現上傳照片以及回顯 一、安裝Element Plus二、案例1、基本示例 三、進階案例1、代碼2、代碼解釋1、上傳接口展示2、查詢接口展示組件屬性 3、效果展示 一、安裝Element Plus 使用 Element Plus 組件庫來實現上傳照片和回顯同樣很簡單&#xff0c;你可以按照以下步驟進行…

用棧實現隊列(C語言)

目錄 題目題目分析 代碼棧的實現結構體。棧的初始化棧的銷毀 入棧刪除查找頂部數據判空 答案結構體初始化插入數據刪除數據獲取隊列開頭元素判空銷毀棧 題目 題目分析 鏈接: 題目 請你僅使用兩個棧實現先入先出隊列。隊列應當支持一般隊列支持的所有操作&#xff08;push、po…

數據庫查詢中——having與where的用法

數據庫查詢中——having與where的用法 HAVING 子句在 SQL 中主要用于與 GROUP BY 子句一起使用&#xff0c;以過濾聚合函數的結果。當你使用 GROUP BY 對數據進行分組&#xff0c;并希望基于這些分組后的數據進一步過濾時&#xff0c;你會使用 HAVING 子句。 HAVING 子句通常與…

pyside6下沒有designer.exe、pyside6-uic.exe等

使用conda安裝的pyside6&#xff08;conda install pyside6&#xff09;&#xff0c;發現pyside6目錄下沒有designer.exe、pyside6-uic.exe等&#xff1b;designer.exe在Miniconda3/Library/bin下 pyside6-uic.exe、pyside6-rcc.exe在Miniconda3\Scripts下 但是 使用pip安裝…

企業內網自建yum源 倉庫 | rsync同步方案

文章目錄 1.背景概述2.獲取軟件文件2.1 準備同步腳本如下 2.2 準備例外文件清單2.3 統計源端大小2.3 運行腳本開始同步文件 3. 創建網頁服務3.1 安裝nginx并啟用3.2 修改ngnix配置文件 4 創建repo索引和客戶文件4.1 創建repo索引4.2 創建客戶端文件4.3 客戶端下載repo文件 1.背…

用 Python 編寫網絡爬蟲:從網頁獲取數據并存儲到 Excel 文件

在本篇博客中,我們將介紹如何使用 Python 編寫一個簡單的網絡爬蟲,用于從網頁中提取數據,并將這些數據存儲到 Excel 文件中。我們將使用 Python 中的一些庫來實現這個功能,包括 urllib.request、BeautifulSoup 和 openpyxl。 1. 網絡爬蟲的基本原理 網絡爬蟲是一種程序,…

【MyBatis】MyBatis解析全局配置文件源碼詳解

目錄 一、前言 思維導圖概括 二、配置文件解析過程分析 2.1 配置文件解析入口 2.2 初始化XMLConfigBuilder 2.3 XMLConfigBuilder#parse()方法&#xff1a;解析全局配置文件 2.3.1 解析properties配置 2.3.2 解析settings配置 2.3.2.1 元信息對象&#xff08;MetaClas…

解決移植Metasploitable3到VM虛擬機無網絡的問題

第一步 導入后不要開機&#xff0c;先在虛擬機設置里面將原有的兩個網絡適配器移除。 第二步 接著在選項里面&#xff0c;在客戶機操作系統里面&#xff0c;選擇Microsoft Windwos(W)&#xff0c; 版本選擇Windows Server 2008 R2 x64 第三步 先打開虛擬機&#xff0c;然后…

Python_文件操作_學習

目錄 一、關于文件的打開和關閉 1. 文件的打開 2.文件的關閉 二、文件的讀取 1. 文件的讀_r 2. 使用readline 3.使用readlines 三、文件的寫入 1. 文本的新建寫入 2.文本的追加寫入 四、文件的刪除和重命名 1.文件的重命名 2.文件的刪除 五、文件的定位讀寫 1.t…

RK 11.0 多屏模式下修改鼠標進入方式

要求&#xff1a;主屏在左&#xff0c;副屏在右。這種排列情況下鼠標僅可通過主屏的最右側移入副屏的最左側&#xff0c;或從副屏的最左側移入主屏最右側。 1.RK默認設計 1.1 RK的代碼設計是當sys.mouse.presentation1時&#xff0c;鼠標在屏幕邊緣的時候就會移入另一個屏幕 …

CISP-PTE筆記整理

目錄 漏洞基礎代碼合集 網安基礎 常見名詞 信息收集 環境和變量的配置 HTTP請求頭基礎 HTTP基礎知識 MySql基礎語法 各系統的敏感目錄路徑 工具使用 Hackbar的tips java下載配置 Xray下載配置&使用 burp爆破賬號密碼和C段&注意事項 SqlMap爆破&創建…

Unity Miscellaneous入門

概述 在Unity中有非常多好用的組件&#xff0c;也是Unity為我們提供的方便的開發工具&#xff0c;它的功能可能不是主流的內容&#xff0c;比如渲染&#xff0c;音樂&#xff0c;視頻等等&#xff0c;所有Unity把這些內容統一歸到了一個雜項文件組中。 Unity組件入門篇總目錄-…

Python線程

Python線程 1. 進程和線程 先來了解下進程和線程。 類比&#xff1a; 一個工廠&#xff0c;至少有一個車間&#xff0c;一個車間中至少有一個工人&#xff0c;最終是工人在工作。 一個程序&#xff0c;至少有一個進程&#xff0c;一個進程中至少有一個線程&#xff0c;最終…

langchain實戰-從0到1搭建ai聊天機器人

介紹 當前&#xff0c;人工智能大模型公司如雨后春筍般迅速涌現&#xff0c;例如 OpenAI、文心一言、通義千問等&#xff0c;它們提供了成熟的 API 調用服務。然而&#xff0c;隨之而來的是不同公司的繁瑣協議接入過程&#xff0c;這讓許多開發者感到頭疼不已。有沒有一種統一…

SpringBoot + Redis實現對接口的限流

目錄 前言 什么是限流&#xff1f; 實現限流 創建一個注解類 接著創建一個切面類 前言 在項目中&#xff0c;對于接口的限流&#xff0c;是任何項目都必不可少的一部分&#xff0c;主要是為了防止用戶頻繁的發送請求&#xff0c;對服務器造成壓力。 另外一點就是防止外來攻…

C++之第八課

課程列表 今天我們來學一學C里的一些實用的東西。 1.域寬 說到域寬setw&#xff0c;就叒要加頭文件了。 #include<iomanip> 使用格式是&#xff1a; cout<<setw(5)<<"123"; setw括號里面可以改數字&#xff0c;后面就是輸出內容了&#xff…

COD論文筆記 Boundary-Guided Camouflaged Object Detection

動機 挑戰性任務&#xff1a;偽裝物體檢測&#xff08;COD&#xff09;是一個重要且具有挑戰性的任務&#xff0c;因為偽裝物體往往與背景高度相似&#xff0c;使得準確識別和分割非常困難。現有方法的不足&#xff1a;現有的深度學習方法難以有效識別偽裝物體的結構和細節&am…

MySQL索引、視圖練習

素材 1.學生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 學號&#xff0c;姓名&#xff0c;性別&#xff0c;年齡&#xff0c;所在系 Sno為主鍵 2.課程表&#xff1a;Course (Cno, Cname,) 課程號&#xff0c;課程名 Cno為主鍵 3.學生選課表&#xff1a;SC (Sno…