日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用FFMPEG——4.2.2版本实现提取视频编码解码文件,ffmpeg基础学习。

發布時間:2024/3/12 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用FFMPEG——4.2.2版本实现提取视频编码解码文件,ffmpeg基础学习。 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

FFMPEG基礎學習

視頻解碼,并且輸出到文件。

我通過雷霄驊的博客學習FFMPEG,在學習過程中發現“雷神”的代碼由于版本的問題,很多代碼已經無法在FFMPEG——4.2.2版本中使用,而在網上也有很多教程是基于FFMPEG——3.x.x版本的,因此,特別寫了這篇文章,解決學習“雷神”博客代碼在4.x.x上編譯無法通過的問題。本篇文章最下面的代碼,配置好環境之后,直接復制,然后修改輸入視頻文件的路徑,就可以運行。

特別是在4.x.x版本中av_register_all();這個函數完全不需要。

本程序的輸入文件只要是編碼數據是H264;AAC,解碼數據是YUV420P;PCM格式的都可以正常運行。

本程序輸出的文件格式是:H264;YUV420P;AAC;PCM。

比較大的改動舉例:

1、關于AVFrame結構體在轉碼過程中的初始化:

雷霄驊的例子代碼如下:

pFrameYUV=av_frame_alloc();out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

這些在新版本無法編譯,很多聲明已經否決。

我修改后的初始化代碼如下:

AVFrame* p_z_p_deco_AVFrame = av_frame_alloc();p_z_p_deco_AVFrame->width = p_input_file_v_AVCodecContext->width;p_z_p_deco_AVFrame->height = p_input_file_v_AVCodecContext->height;p_z_p_deco_AVFrame->format = AV_PIX_FMT_YUV420P;av_frame_get_buffer(p_z_p_deco_AVFrame, 4);

以下是ffmpeg4.2.2版本中對于AVFrame結構體的說明。

/*** Allocate an AVFrame and set its fields to default values. The resulting* struct must be freed using av_frame_free().** @return An AVFrame filled with default values or NULL on failure.** @note this only allocates the AVFrame itself, not the data buffers. Those* must be allocated through other means, e.g. with av_frame_get_buffer() or* manually.*/ AVFrame *av_frame_alloc(void);

2、關于編碼和解碼

雷霄驊的例子使用的函數如下:

int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,int *got_picture_ptr,const AVPacket *avpkt);

FFMPEG——4.2.2版本用的解碼的函數是:

int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);

FFMPEG——4.2.2版本用的編碼函數是:

int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame); int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);

3、關于在解碼過程中AVPacket的內存釋放問題

使用如下函數讀取一幀數據以后,*pkt指向的內存空間在讀取的過程中不能直接釋放,需要使用void av_packet_unref(AVPacket *pkt)來減少引用,在左后所有數據讀完之后,才用void av_packet_free(AVPacket **pkt)函數釋放掉空間。

int av_read_frame(AVFormatContext *s, AVPacket *pkt);

其它的有關版本問題就不一一列舉,最后推薦初學者去看看《基于FFmpeg+SDL的視頻播放器的制作——雷霄驊》這些視頻,有利于學習FFMPEG。本段代碼是基于視頻中前四小節內容的更新。

感謝雷霄驊。

/** 解碼實例時間:2020年4月ffmpeg版本:4.2.2 vs版本:Microsoft Visual Studio Enterprise 2019 開發語言:C++特別聲明:本程序是我通過學習雷霄驊 Lei Xiaohua的博客而編寫的,因此,在此向雷霄驊表示敬意。雷霄驊的博客地址:https://blog.csdn.net/leixiaohua1020 所需知識背景:“視音頻數據處理入門:RGB、YUV像素數據處理”,鏈接地址:https://blog.csdn.net/leixiaohua1020/article/details/50534150“視音頻數據處理入門:PCM音頻采樣數據處理”,鏈接地址:https://blog.csdn.net/leixiaohua1020/article/details/50534316“視音頻數據處理入門:H.264視頻碼流解析”,鏈接地址:https://blog.csdn.net/leixiaohua1020/article/details/50534369“視音頻數據處理入門:AAC音頻碼流解析”,鏈接地址:https://blog.csdn.net/leixiaohua1020/article/details/50535042 說明:本程序實現了解碼本地視頻,并且分別輸出解碼的音視頻文件到文件。通過本程序可以了解整個ffmpeg最簡單的解碼流程。程序為了方便閱讀,沒有采用面向對象編程。本程序能完成雷霄驊的《基于FFmpeg+SDL的視頻播放器的制作——雷霄驊》視頻前四小節的內容。 */ extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" } #include <iostream> #include <fstream> using namespace std;int main() {//本地輸入的文件路徑const char* p_intputFilePath = "sintel.ts";if(p_intputFilePath == NULL) {cout << "請輸入文件路徑!" << endl;return -1;}//獲取文件格式上下文AVFormatContext* p_inptu_file_AVFormatContext = avformat_alloc_context();//打開文件if(avformat_open_input(&p_inptu_file_AVFormatContext, p_intputFilePath, NULL, NULL) != 0) {cout << "文件打開失敗" << endl;return -1;};//獲取文件流信息if(avformat_find_stream_info(p_inptu_file_AVFormatContext, NULL) < 0) {cout << "獲取信息失敗" << endl;return -1;}//獲取到音頻,視頻索引int audioIndex = av_find_best_stream(p_inptu_file_AVFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, 0, NULL);int vedioIndex = av_find_best_stream(p_inptu_file_AVFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, 0, NULL);//找到音頻流和視頻流AVStream* p_input_file_a_AVStream = p_inptu_file_AVFormatContext->streams[audioIndex];AVStream* p_input_file_v_AVStream = p_inptu_file_AVFormatContext->streams[vedioIndex];//獲取到解碼器AVCodec* p_input_file_a_AVCodec = avcodec_find_decoder(p_input_file_a_AVStream->codecpar->codec_id);AVCodec* p_input_file_v_AVCodec = avcodec_find_decoder(p_input_file_v_AVStream->codecpar->codec_id);//獲取音頻,視頻的AVCodecContext。特別注意,ffmpeg4.2.2版本提倡使用AVCodecParameters。AVCodecContext* p_input_file_a_AVCodecContext = avcodec_alloc_context3(NULL);avcodec_parameters_to_context(p_input_file_a_AVCodecContext, p_input_file_a_AVStream->codecpar);AVCodecContext* p_input_file_v_AVCodecContext = avcodec_alloc_context3(NULL);avcodec_parameters_to_context(p_input_file_v_AVCodecContext, p_input_file_v_AVStream->codecpar);//是否含有視頻流和音頻流(一般都包含)if(audioIndex < 0) {cout << "此文件不包含音頻流或者沒有解碼器" << endl;}if(vedioIndex < 0) {cout << "此文件不包含視頻流或者沒有解碼器" << endl;} //打開音頻,視頻的解碼器if(avcodec_open2(p_input_file_a_AVCodecContext, p_input_file_a_AVCodec, NULL) < 0) {cout << "音頻解碼器打開失敗!" << endl; return -1;}if(avcodec_open2(p_input_file_v_AVCodecContext, p_input_file_v_AVCodec, NULL) < 0) {cout << "視頻解碼器代開失敗!" << endl;return -1;}cout << "-------------------------------------- 輸出信息開始位置 ---------------------------------" << endl;av_dump_format(p_inptu_file_AVFormatContext, 0, p_intputFilePath, 0);cout << "-------------------------------------- 輸出信息結束位置 ---------------------------------" << endl;//讀取一幀數據存放空間AVPacket* p_read_frame_AVPacket = av_packet_alloc();//解碼一幀數據存放空間AVFrame* p_deco_AVFrame = av_frame_alloc();//轉碼一幀數據存放空間AVFrame* p_z_p_deco_AVFrame = av_frame_alloc();p_z_p_deco_AVFrame->width = p_input_file_v_AVCodecContext->width;p_z_p_deco_AVFrame->height = p_input_file_v_AVCodecContext->height;p_z_p_deco_AVFrame->format = AV_PIX_FMT_YUV420P;av_frame_get_buffer(p_z_p_deco_AVFrame, 4);//轉碼格式設置SwsContext* img_convert_ctx = NULL;//視頻編碼的數據輸出到out_file_h264.h264文件ofstream out_file_h264("out_file_h264.h264", ios::binary);//視頻解碼的數據輸出到out_file_yuv240p.yuvofstream out_file_yuv240p("out_file_yuv240p.yuv", ios::binary);//音頻編碼的數據輸出到out_file_aac.pcmofstream out_file_acc("out_file_aac.aac", ios::binary);//音頻解碼的數據輸出到out_file_pcm.pcmofstream out_file_pcm("out_file_pcm.pcm", ios::binary);int re = 0;int v_lenth = p_input_file_v_AVCodecContext->width * p_input_file_v_AVCodecContext->height;while(av_read_frame(p_inptu_file_AVFormatContext, p_read_frame_AVPacket) >= 0) {//輸出編碼數據if(p_read_frame_AVPacket->stream_index == vedioIndex) {//輸出視頻編碼數據out_file_h264.write((char*) p_read_frame_AVPacket->data, p_read_frame_AVPacket->size);//解碼視頻re = avcodec_send_packet(p_input_file_v_AVCodecContext, p_read_frame_AVPacket);if(re == 0) {while(avcodec_receive_frame(p_input_file_v_AVCodecContext, p_deco_AVFrame) == 0) {//這里需要轉換一下數據 img_convert_ctx = sws_getContext(p_deco_AVFrame->width, p_deco_AVFrame->height, p_input_file_v_AVCodecContext->pix_fmt,p_input_file_v_AVCodecContext->width, p_input_file_v_AVCodecContext->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);sws_scale(img_convert_ctx, p_deco_AVFrame->data, p_deco_AVFrame->linesize, 0, p_input_file_v_AVCodecContext->height,p_z_p_deco_AVFrame->data, p_z_p_deco_AVFrame->linesize);//輸出視頻解碼數據out_file_yuv240p.write((char*) p_z_p_deco_AVFrame->data[0], v_lenth);out_file_yuv240p.write((char*) p_z_p_deco_AVFrame->data[1], v_lenth / 4);out_file_yuv240p.write((char*) p_z_p_deco_AVFrame->data[2], v_lenth / 4);}}else {cout << "視頻解解碼失敗" << endl;break;}}else {//輸出音頻編碼數據out_file_acc.write((char*) p_read_frame_AVPacket->data, p_read_frame_AVPacket->size);//解碼音頻re = avcodec_send_packet(p_input_file_a_AVCodecContext, p_read_frame_AVPacket);if(re == 0) {while(avcodec_receive_frame(p_input_file_a_AVCodecContext, p_deco_AVFrame) == 0) {//輸出音頻解碼數據for(int i = 0; i < p_deco_AVFrame->nb_samples; i++) {for(int j = 0; j < p_deco_AVFrame->channels; j++) { out_file_pcm.write((char*) p_deco_AVFrame->data[j], av_get_bytes_per_sample(p_input_file_a_AVCodecContext->sample_fmt));} } }}else {cout << "音頻解碼失敗" << endl;break;}}//減少引用av_packet_unref(p_read_frame_AVPacket);}//釋放內存out_file_pcm.close();out_file_acc.close();out_file_yuv240p.close();out_file_h264.close();av_frame_free(&p_z_p_deco_AVFrame);av_frame_free(&p_deco_AVFrame);av_packet_free(&p_read_frame_AVPacket);avcodec_free_context(&p_input_file_a_AVCodecContext);avcodec_free_context(&p_input_file_v_AVCodecContext);avformat_free_context(p_inptu_file_AVFormatContext);

?

給出觀看雷霄驊錄制的視頻地址:基于FFmpeg+SDL的視頻播放器的制作——雷霄驊

總結

以上是生活随笔為你收集整理的使用FFMPEG——4.2.2版本实现提取视频编码解码文件,ffmpeg基础学习。的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。