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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

ffmpeg architecture(下)

發(fā)布時(shí)間:2023/11/28 生活经验 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ffmpeg architecture(下) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ffmpeg architecture(下)

第3章-轉(zhuǎn)碼

TLDR;給我看代碼和執(zhí)行。

$ make run_transcoding

我們將跳過一些細(xì)節(jié),但是請放心:源代碼可在github上找到。

在本章中,我們將創(chuàng)建一個(gè)用C編寫的極簡代碼轉(zhuǎn)換器,可以使用FFmpeg / libav庫(尤其是libavcodec,libavformat和libavutil)將H264編碼的視頻轉(zhuǎn)換為H265。

只是快速回顧一下:該AVFormatContext是媒體文件格式的抽象,又名容器(例如:MKV,MP4,WEBM,TS)。的AV流表示每種類型的用于給定格式(例如:音頻,視頻,字幕,元數(shù)據(jù))的數(shù)據(jù)。所述AVPacket是從所獲得的壓縮數(shù)據(jù)的切片AVStream可以由一個(gè)解碼avcodec中:產(chǎn)生稱為原始數(shù)據(jù)(例如AV1,H264,VP9,HEVC)AVFrame。

轉(zhuǎn)碼

讓我們從簡單的轉(zhuǎn)換操作開始,然后我們可以基于此代碼構(gòu)建,第一步是加載輸入文件。

//分配一個(gè)AVFormatContextavfc = avformat_alloc_context();//打開輸入流并讀取標(biāo)題。avformat_open_input(avfc,in_filename, NULL,NULL);//讀取媒體文件的數(shù)據(jù)包以獲取流信息。avformat_find_stream_info(avfc, NULL);

現(xiàn)在,我們要設(shè)置解碼器,它AVFormatContext將使我們能夠訪問所有AVStream組件,并且對于每個(gè)組件,我們都可以獲取它們AVCodec并創(chuàng)建特定組件AVCodecContext,最后我們可以打開給定的編解碼器,以便繼續(xù)進(jìn)行解碼處理。

所述AVCodecContext持有如比特率,幀速率,采樣率,信道,高度,和許多其它有關(guān)的媒體數(shù)據(jù)的配置等。

對于(int i = 0 ; i nb_streams; i ++){ AVStream * avs = avfc-> 流 [i]; AVCodec * avc = avcodec_find_decoder(avs-> codecpar- > codec_id); AVCodecContext * avcc = avcodec_alloc_context3(* avc); avcodec_parameters_to_context(* avcc,avs-> codecpar); avcodec_open2(* avcc,* avc,NULL);}

我們還需要準(zhǔn)備輸出媒體文件以進(jìn)行多路傳輸,我們首先為輸出分配內(nèi)存AVFormatContext。我們以輸出格式創(chuàng)建每個(gè)流。為了正確打包流,我們從解碼器復(fù)制編解碼器參數(shù)。

我們設(shè)置標(biāo)志 AV_CODEC_FLAG_GLOBAL_HEADER告訴編碼器它可以使用全局頭文件,最后打開輸出文件進(jìn)行寫入并保留頭文件。

avformat_alloc_output_context2(&encoder_avfc,NULL,NULL,out_filename); AVStream * avs = avformat_new_stream(encoder_avfc,NULL);avcodec_parameters_copy(avs-> codecpar,解碼器_avs-> codecpar); 如果(encoder_avfc-> oformat-> flags和AVFMT_GLOBALHEADER) encoder_avfc-> flags | = AV_CODEC_FLAG_GLOBAL_HEADER; avio_open(&encoder_avfc-> pb,編碼器->文件名,AVIO_FLAG_WRITE);avformat_write_header(encoder- > avfc,&muxer_opts);

我們AVPacket從解碼器獲取,調(diào)整時(shí)間戳,并將數(shù)據(jù)包正確寫入輸出文件。即使函數(shù)av_interleaved_write_frame說“寫幀”,我們?nèi)栽诖鎯?shù)據(jù)包。通過將流預(yù)告片寫入文件中,我們完成了轉(zhuǎn)換過程。

AVFrame * input_frame = av_frame_alloc();AVPacket * input_packet = av_packet_alloc(); 而(av_read_frame(decoder_avfc,input_packet)> = 0){ av_packet_rescale_ts(input_packet,解碼器_視頻_avs-> time_base,編碼器 _視頻_avs- > time_base); av_interleaved_write_frame(* avfc,input_packet)< 0));} av_write_trailer(encoder_avfc);

轉(zhuǎn)碼

前面展示了一個(gè)簡單的transmuxer程序,現(xiàn)在我們將添加對文件進(jìn)行編碼的功能,尤其是使它能夠?qū)⒁曨l從轉(zhuǎn)換h264為h265。

在準(zhǔn)備好解碼器之后,但在安排輸出媒體文件之前,我們將設(shè)置編碼器。

AVStream在編碼器中創(chuàng)建視頻,avformat_new_stream
使用AVCodec所謂的libx265,avcodec_find_encoder_by_name
AVCodecContext在創(chuàng)建的編解碼器中創(chuàng)建基礎(chǔ),avcodec_alloc_context3
設(shè)置轉(zhuǎn)碼會話的基本屬性,并
打開編解碼器,然后將參數(shù)從上下文復(fù)制到流中。avcodec_open2和avcodec_parameters_from_context

AVRational input_framerate = av_guess_frame_rate(decoder_avfc,decoder_video_avs,NULL);AVStream * video_avs = avformat_new_stream(encoder_avfc,NULL); char * codec_name = “ libx265 ” ;char * codec_priv_key = “ x265-params ” ;//我們將為x265使用內(nèi)部選項(xiàng)// //禁用場景更改檢測,然后修復(fù)// 60幀的GOP。char * codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0 ” ; AVCodec * video_avc = avcodec_find_encoder_by_name(codec_name);AVCodecContext * video_avcc = avcodec_alloc_context3(video_avc);//編碼器編解碼器參數(shù)av_opt_set(sc-> video_avcc-> priv_data,codec_priv_key,codec_priv_value, 0);video_avcc-> height =解碼器_ctx-> height;video_avcc-> width =解碼器_ctx-> width;video_avcc-> pix_fmt = video_avc-> pix_fmts [ 0 ];//控制率 video_avcc-> bit_rate = 2 * 1000 * 1000 ;video_avcc-> rc_buffer_size = 4 * 1000 * 1000 ;video_avcc-> rc_max_rate = 2 * 1000 * 1000 ;video_avcc-> rc_min_rate = 2.5 * 1000 * 1000 ;//時(shí)基video_avcc-> time_base = av_inv_q(input_framerate);video_avs-> time_base = sc-> video_avcc-> time_base; avcodec_open2(sc-> video_avcc,sc-> video_avc,NULL);avcodec_parameters_from_context(sc-> video_avs-> codecpar,sc-> video_avcc);

我們需要擴(kuò)展解碼循環(huán)以進(jìn)行視頻流轉(zhuǎn)碼:

將空發(fā)送AVPacket給解碼器,avcodec_send_packet 接收未壓縮的AVFrame,avcodec_receive_frame
開始對該原始幀進(jìn)行轉(zhuǎn)碼,發(fā)送原始幀, avcodec_send_frame
根據(jù)我們的編解碼器接收壓縮的文件AVPacket,avcodec_receive_packet
設(shè)置時(shí)間戳,并 av_packet_rescale_ts 將其寫入輸出文件。 av_interleaved_write_frame

AVFrame * input_frame = av_frame_alloc();AVPacket * input_packet = av_packet_alloc(); 而(av_read_frame(decoder_avfc,input_packet)> = 0){ int響應(yīng)= avcodec_send_packet(decoder_video_avcc,input_packet); while(響應(yīng)> = 0){ 響應(yīng)= avcodec_receive_frame(decoder_video_avcc,input_frame); if(響應(yīng)== AVERROR(EAGAIN)|| response == AVERROR_EOF){ 中斷 ; } else if(response < 0){ 返回響應(yīng); } if(響應(yīng)> = 0){ 編碼(encoder_avfc,decoder_video_avs,encoder_video_avs,decoder_video_avcc,input_packet-> stream_index); } av_frame_unref(input_frame); } av_packet_unref(input_packet);}av_write_trailer(encoder_avfc); //使用的函數(shù)int 編碼(AVFormatContext * avfc,AVStream * dec_video_avs,AVStream * enc_video_avs,AVCodecContext video_avcc int索引){ AVPacket * output_packet = av_packet_alloc(); int response = avcodec_send_frame(video_avcc,input_frame); while(響應(yīng)> = 0){ 響應(yīng)= avcodec_receive_packet(video_avcc,output_packet); if(響應(yīng)== AVERROR(EAGAIN)|| response == AVERROR_EOF){ 中斷 ; } else if(響應(yīng)< 0){ return - 1 ; } output_packet-> stream_index = index ; output_packet-> 持續(xù)時(shí)間 = enc_video_avs-> 那么time_base。den / enc_video_avs-> time_base。num / dec_video_avs-> avg_frame_rate。num * dec_video_avs-> avg_frame_rate。巢穴 ; av_packet_rescale_ts(output_packet,dec_video_avs-> time_base,enc_video_avs-> time_base); 響應(yīng)= av_interleaved_write_frame(avfc,output_packet); } av_packet_unref(output_packet); av_packet_free(&output_packet); 返回 0 ;}

我們將媒體流從轉(zhuǎn)換h264為h265,正如預(yù)期的那樣h265,媒體文件的版本小于,h264但創(chuàng)建的程序能夠:

/ * * H264-> H265 *音頻->重混合(未觸摸) * MP4-MP4 * / StreamingParams sp = { 0 }; sp.copy_audio = 1 ; sp.copy_video = 0 ; sp.video_codec = “ libx265 ”; sp.codec_priv_key = “ x265-params ” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0 ” ; / * * H264-> H264(固定gop) *音頻->重混合(未觸摸) * MP4-MP4 * / StreamingParams sp = { 0 }; sp.copy_audio = 1 ; sp.copy_video = 0 ; sp.video_codec = “ libx264 ”; sp.codec_priv_key = “ x264參數(shù)” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0:force-cfr = 1 ” ; / * * H264-> H264(固定gop) 音頻->重混合(未修改) MP4- 片段MP4 * / StreamingParams sp = { 0 }; sp.copy_audio = 1 ; sp.copy_video = 0 ; sp.video_codec = “ libx264 ”; sp.codec_priv_key = “ x264參數(shù)” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0:force-cfr = 1 ” ; sp.muxer_opt_key = “ movflags ”; sp.muxer_opt_value = “ frag_keyframe + empty_moov + default_base_moof ” ; / * * H264-> H264(固定gop) *音頻-> AAC * MP4-MPEG-TS * / StreamingParams sp = { 0 }; sp.copy_audio = 0 ; sp.copy_video = 0 ; sp.video_codec = “ libx264 ”; sp.codec_priv_key = “ x264參數(shù)” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0:force-cfr = 1 ” ; sp.audio_codec = “ aac ” ; sp.output_extension = “ .ts ” ; / * WIP:P->它不在VLC上播放,最終比特率很高 * H264-> VP9 *音頻-> Vorbis * MP4-WebM * / // StreamingParams sp = {0}; // sp.copy_audio = 0; // sp.copy_video = 0; // sp.video_codec =“ libvpx-vp9”; // sp.audio_codec =“ libvorbis”; // sp.output_extension =“ .webm”;

現(xiàn)在,說實(shí)話,這是難度比我想這會是我不得不挖掘到FFmpeg的命令行的源代碼和測試了很多,我覺得我失去了一些東西,因?yàn)槲也坏貌粓?zhí)行force-cfr的h264工作而且我仍然看到一些警告消息,例如warning messages (forced frame type (5) at 80 was changed to frame type (3))。

總結(jié)

以上是生活随笔為你收集整理的ffmpeg architecture(下)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。