當前位置:首頁 » 操作系統 » h264源碼

h264源碼

發布時間: 2025-04-07 18:24:25

Ⅰ 如何讓WebRTC支持H264

編譯選項調整

WebRTC能支持H264,但在Linux下編譯時默認未啟用。關鍵在於rtc_use_h264開關,控制著是否使用H264。通過在webrtc/webrtc.gni文件中調整proprietary_codecs選項,即可開啟H264支持。

調整proprietary_codecs為true後,打開rtc_use_h264選項,使能OpenH264編碼支持。WebRTC內部會使用ffmpeg來解碼H264,需要確保rtc_initialize_ffmpeg選項為true以使ffmpeg初始化。

調整配置後,運行gn gen命令生成構建文件,驗證選項是否生效。使用命令檢查Current Value為true時,說明已成功啟用H264支持。

要完全啟用H264,還需調整C++代碼中FFMPEG_H264_DECODER宏,確保avcodec_register_all()方法注冊H264解碼器。

此外,注意Linux編譯WebRTC時,生成的構建文件可能缺少ffmpeg的H264解碼器源代碼。因此,在third_party/ffmpeg/ffmpeg_generated.gni文件中打開相關條件,確保H264解碼器可用。

在C++音視頻開發學習中,需要調整代碼來改變默認的編解碼順序,將H264置於優先位置,以適應不同的應用需求。

使用特定模塊編譯並重新構建native app後,H264支持即可在WebRTC中生效。

關於WebRTC使用H264會黑屏的問題,WebRTC以出色的QoS而著稱,支持VP8和VP9視頻,但在使用H264時,質量可能不如VP8/VP9,存在卡頓、時延增加和塊狀效應等問題。

深入分析WebRTC的QoS策略後發現,H264的FEC(前向糾錯)被關閉,這與VP8/VP9不同。此外,H264的FEC存在BUG,可能導致解碼失敗,引起視頻卡頓。H264的FEC機制與VP8/VP9不兼容,以及RTP組包協議的差異,導致H264無法啟用時間分級。

綜上所述,WebRTC使用H264時,需調整編譯選項、代碼配置以及理解其QoS策略與編碼器特性,以確保穩定性和性能。

Ⅱ FFmpeg視頻編碼 YUV420P編碼H264

//第一步:注冊組件->編碼器、解碼器等等…

    av_register_all();

    //第二步:初始化封裝格式上下文->視頻編碼->處理為視頻壓縮數據格式

    AVFormatContext *avformat_context = avformat_alloc_context();

    //注意事項:FFmepg程序推測輸出文件類型->視頻壓縮數據格式類型

    const char *coutFilePath = [outFilePath UTF8String];

    //得到視頻壓縮數據格式類型(h264、h265、mpeg2等等...)

    AVOutputFormat *avoutput_format = av_guess_format(NULL, coutFilePath, NULL);

    //指定類型

    avformat_context->oformat = avoutput_format;

    //第三步:打開輸出文件

    //參數一:輸出流

    //參數二:輸出文件

    //參數三:許可權->輸出到文件中

    if (avio_open(&avformat_context->pb, coutFilePath, AVIO_FLAG_WRITE) < 0) {

        NSLog(@"打開輸出文件失敗");

        return;

    }

    //第四步:創建輸出碼流->創建了一塊內存空間->並不知道他是什麼類型流->希望他是視頻流

    AVStream *av_video_stream = avformat_new_stream(avformat_context, NULL);

    //第五步:查找視頻編碼器

    //1、獲取編碼器上下文

    AVCodecContext *avcodec_context = av_video_stream->codec;

    //2、設置編解碼器上下文參數->必需設置->不可少

    //目標:設置為是一個視頻編碼器上下文->指定的是視頻編碼器

    //上下文種類:視頻解碼器、視頻編碼器、音頻解碼器、音頻編碼器

    //2.1 設置視頻編碼器ID

    avcodec_context->codec_id = avoutput_format->video_codec;

    //2.2 設置編碼器類型->視頻編碼器

    //視頻編碼器->AVMEDIA_TYPE_VIDEO

    //音頻編碼器->AVMEDIA_TYPE_AUDIO

    avcodec_context->codec_type = AVMEDIA_TYPE_VIDEO;

    //2.3 設置讀取像素數據格式->編碼的是像素數據格式->視頻像素數據格式->YUV420P(YUV422P、YUV444P等等...)

    //注意:這個類型是根據你解碼的時候指定的解碼的視頻像素數據格式類型

    avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P;

    //2.4 設置視頻寬高->視頻尺寸

    avcodec_context->width = 640;

    avcodec_context->height = 352;

    //2.5 設置幀率->表示每秒25幀

    //視頻信息->幀率 : 25.000 fps

    //f表示:幀數

    //ps表示:時間(單位:每秒)

    avcodec_context->time_base.num = 1;

    avcodec_context->time_base.den = 25;

    //2.6 設置碼率

    //2.6.1 什麼是碼率?

    //含義:每秒傳送的比特(bit)數單位為 bps(Bit Per Second),比特率越高,傳送數據速度越快。

    //單位:bps,"b"表示數據量,"ps"表示每秒

    //目的:視頻處理->視頻碼率

    //2.6.2 什麼是視頻碼率?

    //含義:視頻碼率就是數據傳輸時單位時間傳送的數據位數,一般我們用的單位是kbps即千位每秒

    //視頻碼率計算如下?

    //基本的演算法是:【碼率】(kbps)=【視頻大小 - 音頻大小】(bit位) /【時間】(秒)

    //例如:Test.mov時間 = 24,文件大小(視頻+音頻) = 1.73MB

    //視頻大小 = 1.34MB(文件佔比:77%) = 1.34MB * 1024 * 1024 * 8 = 位元組大小 = 468365位元組 = 468Kbps

    //音頻大小 = 376KB(文件佔比:21%)

    //計算出來值->碼率 : 468Kbps->表示1000,b表示位(bit->位)

    //總結:碼率越大,視頻越大

    avcodec_context->bit_rate = 468000;

    //2.7 設置GOP->影響到視頻質量問題->畫面組->一組連續畫面

    //MPEG格式畫面類型:3種類型->分為->I幀、P幀、B幀

    //I幀->內部編碼幀->原始幀(原始視頻數據)

    //    完整畫面->關鍵幀(必需的有,如果沒有I,那麼你無法進行編碼,解碼)

    //    視頻第1幀->視頻序列中的第一個幀始終都是I幀,因為它是關鍵幀

    //P幀->向前預測幀->預測前面的一幀類型,處理數據(前面->I幀、B幀)

    //    P幀數據->根據前面的一幀數據->進行處理->得到了P幀

    //B幀->前後預測幀(雙向預測幀)->前面一幀和後面一幀

    //    B幀壓縮率高,但是對解碼性能要求較高。

    //總結:I只需要考慮自己 = 1幀,P幀考慮自己+前面一幀 = 2幀,B幀考慮自己+前後幀 = 3幀

    //    說白了->P幀和B幀是對I幀壓縮

    //每250幀,插入1個I幀,I幀越少,視頻越小->默認值->視頻不一樣

    avcodec_context->gop_size = 250;

    //2.8 設置量化參數->數學演算法(高級演算法)->不講解了

    //總結:量化系數越小,視頻越是清晰

    //一般情況下都是默認值,最小量化系數默認值是10,最大量化系數默認值是51

    avcodec_context->qmin = 10;

    avcodec_context->qmax = 51;

    //2.9 設置b幀最大值->設置不需要B幀

    avcodec_context->max_b_frames = 0;

    //第二點:查找編碼器->h264

    //找不到編碼器->h264

    //重要原因是因為:編譯庫沒有依賴x264庫(默認情況下FFmpeg沒有編譯進行h264庫)

    //第一步:編譯h264庫

    AVCodec *avcodec = avcodec_find_encoder(avcodec_context->codec_id);

    if (avcodec == NULL) {

        NSLog(@"找不到編碼器");

        return;

    }

    NSLog(@"編碼器名稱為:%s", avcodec->name);

    //第六步:打開h264編碼器

    //缺少優化步驟?

    //編碼延時問題

    //編碼選項->編碼設置

    AVDictionary *param = 0;

    if (avcodec_context->codec_id == AV_CODEC_ID_H264) {

        //需要查看x264源碼->x264.c文件

        //第一個值:預備參數

        //key: preset

        //value: slow->慢

        //value: superfast->超快

        av_dict_set(¶m, "preset", "slow", 0);

        //第二個值:調優

        //key: tune->調優

        //value: zerolatency->零延遲

        av_dict_set(¶m, "tune", "zerolatency", 0);

    }

    if (avcodec_open2(avcodec_context, avcodec, ¶m) < 0) {

        NSLog(@"打開編碼器失敗");

        return;

    }

    //第七步:寫入文件頭信息

    avformat_write_header(avformat_context, NULL);

    //第8步:循環編碼yuv文件->視頻像素數據(yuv格式)->編碼->視頻壓縮數據(h264格式)

    //8.1 定義一個緩沖區

    //作用:緩存一幀視頻像素數據

    //8.1.1 獲取緩沖區大小

    int buffer_size = av_image_get_buffer_size(avcodec_context->pix_fmt,

                                               avcodec_context->width,

                                               avcodec_context->height,

                                               1);

    //8.1.2 創建一個緩沖區

    int y_size = avcodec_context->width * avcodec_context->height;

    uint8_t *out_buffer = (uint8_t *) av_malloc(buffer_size);

    //8.1.3 打開輸入文件

    const char *cinFilePath = [inFilePath UTF8String];

    FILE *in_file = fopen(cinFilePath, "rb");

    if (in_file == NULL) {

        NSLog(@"文件不存在");

        return;

    }

    //8.2.1 開辟一塊內存空間->av_frame_alloc

    //開辟了一塊內存空間

    AVFrame *av_frame = av_frame_alloc();

    //8.2.2 設置緩沖區和AVFrame類型保持一直->填充數據

    av_image_fill_arrays(av_frame->data,

                         av_frame->linesize,

                         out_buffer,

                         avcodec_context->pix_fmt,

                         avcodec_context->width,

                         avcodec_context->height,

                         1);

    int i = 0;

    //9.2 接收一幀視頻像素數據->編碼為->視頻壓縮數據格式

    AVPacket *av_packet = (AVPacket *) av_malloc(buffer_size);

    int result = 0;

    int current_frame_index = 1;

    while (true) {

        //8.1 從yuv文件裡面讀取緩沖區

        //讀取大小:y_size * 3 / 2

        if (fread(out_buffer, 1, y_size * 3 / 2, in_file) <= 0) {

            NSLog(@"讀取完畢...");

            break;

        }else if (feof(in_file)) {

            break;

        }

        //8.2 將緩沖區數據->轉成AVFrame類型

        //給AVFrame填充數據

        //8.2.3 void * restrict->->轉成->AVFrame->ffmpeg數據類型

        //Y值

        av_frame->data[0] = out_buffer;

        //U值

        av_frame->data[1] = out_buffer + y_size;

        //V值

        av_frame->data[2] = out_buffer + y_size * 5 / 4;

        av_frame->pts = i;

        //注意時間戳

        i++;

        //總結:這樣一來我們的AVFrame就有數據了

        //第9步:視頻編碼處理

        //9.1 發送一幀視頻像素數據

        avcodec_send_frame(avcodec_context, av_frame);

        //9.2 接收一幀視頻像素數據->編碼為->視頻壓縮數據格式

        result =avcodec_receive_packet(avcodec_context, av_packet);

        //9.3 判定是否編碼成功

        if (result == 0) {

            //編碼成功

            //第10步:將視頻壓縮數據->寫入到輸出文件中->outFilePath

            av_packet->stream_index = av_video_stream->index;

            result =av_write_frame(avformat_context, av_packet);

            NSLog(@"當前是第%d幀", current_frame_index);

            current_frame_index++;

            //是否輸出成功

            if (result < 0) {

                NSLog(@"輸出一幀數據失敗");

                return;

            }

        }

    }

    //第11步:寫入剩餘幀數據->可能沒有

    flush_encoder(avformat_context, 0);

    //第12步:寫入文件尾部信息

    av_write_trailer(avformat_context);

    //第13步:釋放內存

    avcodec_close(avcodec_context);

    av_free(av_frame);

    av_free(out_buffer);

    av_packet_free(&av_packet);

    avio_close(avformat_context->pb);

    avformat_free_context(avformat_context);

    fclose(in_file);

熱點內容
蘭州win10ftp伺服器託管 發布:2025-04-07 21:46:32 瀏覽:742
android視頻編碼 發布:2025-04-07 21:43:56 瀏覽:490
ice伺服器被炸之前長什麼樣子 發布:2025-04-07 21:39:34 瀏覽:826
資料庫軟體開發 發布:2025-04-07 21:38:41 瀏覽:323
中石化優化專區伺服器是什麼意思 發布:2025-04-07 21:25:03 瀏覽:371
怎麼清理手機usb存儲器 發布:2025-04-07 21:20:23 瀏覽:817
怎麼打開系統配置 發布:2025-04-07 21:17:19 瀏覽:704
家庭風險規劃怎麼配置 發布:2025-04-07 21:13:09 瀏覽:368
如何用雲伺服器看國外 發布:2025-04-07 21:13:07 瀏覽:458
寶寶玩編程 發布:2025-04-07 20:56:12 瀏覽:704