新手學習FFmpeg - 調用API完成錄屏並進行H.264編碼


Screen Record H.264

目前在網絡傳輸視頻/音頻流都一般會采用H.264進行編碼,所以嘗試調用FFMPEG API完成Mac錄屏功能,同時編碼為H.264格式。

在上一篇文章中,通過調用FFmpeg API完成了Mac平台下的錄屏功能。在本篇中,對上次的錄屏進行優化,將采集到的視頻流編碼為H.264格式,同時設定FPS和分辨率。

因為是對上次錄屏功能的優化,因此處理思路仍然分為三部分:

  1. 打開輸入設備(默認的屏幕設備)
  2. 初始化輸出設備(mp4文件)
  3. 內容轉碼

和上次使用的API對比,本次主要增加了涉及到H.264參數設定和H.264 pts/dts 設定的API:

  1. avcodec_parameters_from_context
  2. av_rescale_q

初始化輸入設備

仍然采用上篇中打開設備的方法:

  1. 通過av_find_input_format("avfoundation")獲取AVInputFormat。
  2. 通過avformat_open_input 打開指定的屏幕設備。

然后FFmpeg會返回此設備中的數據流,而FFmpeg處理數據流一般都遵循:確定codec(編碼 or 解碼)->初始化codec上下文參數->打開codec,這三步。 針對輸入設備也就是下面的順序:

avcodec_find_decoder -> avcodec_alloc_context3 -> avcodec_open2

AVInputFormat會有多個數據流(視頻流/音頻流),所以首先找到需要處理的流:

codecpar->codec_type == AVMEDIA_TYPE_VIDEO

然后依次調用avcodec_find_decoder,avcodec_alloc_context3avcodec_open2來初始化codec。

初始化輸出設備

最后是將視頻數據編碼為H.264,並封裝到MP4容器中。所以文件名仍設定為out.mp4

打開輸出設備的方法和打開輸入設備方法類似:

avcodec_find_encoder -> avcodec_alloc_context3 -> avcodec_open2 -> avformat_write_header

最后的avformat_write_header不是必須的,只有當容器格式要求寫Header時才會調用。與上篇中不同的時,明確指定輸出CodecContext的編碼器類型:

    outCodecContext->codec_id = AV_CODEC_ID_H264;
    outCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
    outCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
    outCodecContext->bit_rate = 400000; // 2500000
    outCodecContext->width = 1920;
    outCodecContext->height = 1080;

同時H.264對pts和dts有要求,因此需要設定timebase:

    outCodecContext->time_base = (AVRational) {1, 25};

轉碼

有了上次的經驗之后,處理轉碼就會稍顯簡單。 處理流程大致為:

    while av_read_frame
        |
        +---> avcodec_send_packet
                    |
                    +----> while avcodec_receive_frame
                                     | 對每一數據幀進行解碼
                                     | 通過`sws_scale`進行源幀和目標幀的數據轉換
                                     |
                                     +----> avcodec_send_frame
                                               |
                                               +---> while avcodec_receive_packet
                                                             |
                                                             |
                                                             +--->av_interleaved_write_frame (寫入到輸出設備)

轉碼最重要的環節就是在avcodec_receive_frame之后的邏輯。 上面說過H.264對pts有要求,因此這里需要對每一幀添加pts值。

    int64_t now = av_gettime();
    const AVRational codecTimebase = outStream->time_base;
    oframe->pts = av_rescale_q(now, (AVRational) {1, 1000000}, codecTimebase);

在最后寫入到輸出設備之前,仍需要修改pts值:

    if (opacket->pts != AV_NOPTS_VALUE)
        opacket->pts = av_rescale_q(opacket->pts, outCodecContext->time_base, outStream->time_base);

至此就完成了對視頻進行H.264編碼的過程。可以看到和上篇處理過程大致相同,唯一不同的地方就是針對H.264編碼格式進行了一些特殊處理,除此之外大致流程完全一致。

源碼請點擊 https://andy-zhangtao.github.io/ffmpeg-examples/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM