国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

[解決思路]關(guān)于h264裸流合成mp4時時間戳添加問題

這篇具有很好參考價值的文章主要介紹了[解決思路]關(guān)于h264裸流合成mp4時時間戳添加問題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

問題場景:

????????使用GPU編碼(Opencv)生成的h264視頻片段中不包含時間戳信息,且含有B幀,直接合成mp4后會導致播放出現(xiàn)問題(瞬間播放完成)。因此,在合成時需要手動添加時間戳。

心路歷程:

? ? ? ? 發(fā)現(xiàn)生成的視頻會瞬間播放完成后,意識到是時間戳的問題,檢查時間戳代碼:

while (av_read_frame(inputFormatContext, &packet) >= 0) {
    if (packet.pts == AV_NOPTS_VALUE){
        // 判斷pts是否為空
        // 添加時間戳... 
    }
}

? ? ? ? 一開始沒注意到有B幀,想著把pts、dts設(shè)置相等,并且按照間隔遞增就可以了:

AVStream *inStream = inputFormatContext->streams[packet.stream_index];
AVStream *outStream = outputFormatContext->streams[packet.stream_index];

// 計算兩幀之間的間隔,以輸入流的時間基計算
int64_t frameDuration = av_rescale_q(1, av_inv_q(inStream->time_base), inStream->r_frame_rate);
// 轉(zhuǎn)換時間基為輸出流的時間基
int64_t _t = av_rescale_q(frameDuration, inStream->time_base, outStream->time_base);

// 當前幀的時間戳等于上一幀的時間戳加上兩幀之間的間隔
packet.pts = last_pts + _t;
// dts設(shè)置成一樣
packet.dts = packet.pts;

? ? ? ? 對于只有I和P幀的h264流,上述方法可以領(lǐng)流正常播放,但如果h264中有B幀,則會導致在某些播放器上播放異?!?strong>幀顯示順序錯誤,物體“顫抖”著移動。

? ? ? ? 對于含有B幀的視頻,其dts和pts應(yīng)該是按照這種順序進行的:

I B P B P B P
dts 1 2 3 4 5 6 7
pts 1 3 2 5 4 7 6

? ? ? ? 注:dts需要遞增,解碼需要按照順序解碼。任何一幀的pts應(yīng)大于等于dts,因為需要先解碼后才能顯示。因此上述需要調(diào)整:

I B P B P B P
dts 1 2 3 4 5 6 7
pts 2 4 3 6 5 8 7

? ? ? ? 為了使視頻打開時就有畫面能播放,因此需要將第一幀的pts調(diào)整為0,dts是可以為負數(shù)的,但需要保持遞增。調(diào)整后:

I B P B P B P
dts -1 0 1 2 3 4 5
pts 0 2 1 4 3 6 5

? ? ? ? 以上是最簡單的例子,也可以推導出變形:

I B B P B B P
dts -2 -1 0 1 2 3 4
pts 0 2 3 1 5 6 4

? ? ? ? 因此,時間戳的規(guī)律和我們的視頻中有多少連續(xù)的B幀有關(guān)

? ? ? ? 以上討論的假設(shè)都是一個幀組中只有一個I幀的情況下,如果一個GOP中有多個I幀時情況會更復雜一點(沒做整理,本文暫不討論):

I(IDR) B P B P B I B P B P I(IDR) ...
dts 1 2 3 4 5 6 7 8 9 10 11 12
pts 1 3 2 5 4 7 6 9 8 11 10 12

? ? ? ??總結(jié):加時間戳的前提是要知道h264文件幀的類型結(jié)構(gòu)(是否有B幀、連續(xù)的B幀數(shù)量、一個GOP是否有多個I幀)

后記:

? ? ? ? 由于我的文件都是我自己生成的,幀結(jié)構(gòu)都是統(tǒng)一的,因此可以輕松的找出添加時間戳的規(guī)律。但對于不同幀結(jié)構(gòu)的原始流,找出統(tǒng)一規(guī)律還是比較麻煩,本文不再闡述。

? ? ? ? 附對于最簡單的含有B幀的處理代碼(IBPBPBPBP):

// 將多個h264文件合并成mp4文件
int mutexMp4File(){
    // 創(chuàng)建輸出文件   
    // m_outputFile:輸出文件名 xxx.mp4
    AVFormatContext* outputFormatContext = nullptr;
    if (avformat_alloc_output_context2(&outputFormatContext, nullptr, nullptr, m_outputFile.c_str()) < 0) {
        return -1;
    }

    // 準備工作:遍歷輸入文件列表   
    // m_inputFiles:輸入文件名列表
    for (const auto& inputFile : m_inputFiles) {
        // 打開輸入文件
        AVFormatContext* inputFormatContext = nullptr;
        if (avformat_open_input(&inputFormatContext, inputFile.c_str(), nullptr, nullptr) != 0) {
            return -1;
        }

        // 查找輸入文件的流信息
        if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) {
            avformat_close_input(&inputFormatContext);
            avformat_free_context(outputFormatContext);
            return -1;
        }

        // 復制輸入文件的流到輸出文件
        for (unsigned int i = 0; i < inputFormatContext->nb_streams; ++i) {
            // 獲取輸入流
            AVStream* inputStream = inputFormatContext->streams[i];
            // 創(chuàng)建輸出流
            AVStream* outputStream = avformat_new_stream(outputFormatContext, nullptr);
            if (outputStream == nullptr) {
                avformat_close_input(&inputFormatContext);
                avformat_free_context(outputFormatContext);
                return -1;
            }
            // 復制輸入流的編解碼器參數(shù)到輸出流
            if (avcodec_parameters_copy(outputStream->codecpar, inputStream->codecpar) < 0) {
                avformat_close_input(&inputFormatContext);
                avformat_free_context(outputFormatContext);
                return -1;
            }
            // 設(shè)置輸出流的編解碼器標志為"copy"
            outputStream->codecpar->codec_tag = 0;
        }

        // 關(guān)閉輸入文件
        avformat_close_input(&inputFormatContext);
    }

    // 打開輸出文件
    AVIOContext* outputIOContext = nullptr;
    if (avio_open(&outputFormatContext->pb, m_outputFile.c_str(), AVIO_FLAG_WRITE) < 0) {
        avformat_free_context(outputFormatContext);
        return -1;
    }

    // 寫入文件頭部
    if (avformat_write_header(outputFormatContext, nullptr) < 0) {
        avformat_free_context(outputFormatContext);
        return -1;
    }

    int64_t gdts_notime = 0;//拼接多個文件的時間戳

    // 遍歷輸入文件列表,寫入數(shù)據(jù)到輸出文件
    for (const auto& inputFile : m_inputFiles) {
        // 打開輸入文件
        AVFormatContext* inputFormatContext = nullptr;
        if (avformat_open_input(&inputFormatContext, inputFile.c_str(), nullptr, nullptr) != 0) {
            avformat_free_context(outputFormatContext);
            return -1;
        }
        // 查找輸入文件的流信息
        if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) {
            avformat_close_input(&inputFormatContext);
            avformat_free_context(outputFormatContext);
            return -1;
        }

        // 從輸入文件讀取數(shù)據(jù)并寫入輸出文件
        AVPacket packet;
        int64_t p_max_dts = 0;
        int i = 0;
        while (av_read_frame(inputFormatContext, &packet) >= 0) {
            AVStream *inStream = inputFormatContext->streams[packet.stream_index];
            AVStream *outStream = outputFormatContext->streams[packet.stream_index];
            if (packet.pts == AV_NOPTS_VALUE){
                // 起始 只能針對 IBPBPBP 連續(xù)B幀為1的流
                int nalu_type = 0,startIndex = 0;
                if (packet.data[0]==0x00 && packet.data[1]==0x00 && packet.data[2]==0x01){
                    nalu_type = 0x1f & packet.data[3];
                    startIndex = 3;
                }else if(packet.data[0]==0x00 && packet.data[1]==0x00 && packet.data[2]==0x00 && packet.data[3]==0x01){
                    nalu_type = 0x1f & packet.data[4];
                    startIndex = 4;
                }
                
                int64_t frameDuration = av_rescale_q(1, av_inv_q(inStream->time_base), inStream->r_frame_rate);
                int64_t _t = av_rescale_q(frameDuration, inStream->time_base, outStream->time_base);

                p_max_dts = _t*(i+1);
                packet.dts = p_max_dts + gdts_notime - _t;
                int xt = (int)packet.data[startIndex+1] & 0xC0;
                if (nalu_type == 0x05 || nalu_type == 0x06 || nalu_type == 0x07 || nalu_type == 0x08){ //I幀開頭
                    packet.pts = packet.dts + _t;
                }else if(nalu_type == 0x01 && xt == 0x80){ //P幀
                    packet.pts = packet.dts;
                }else if(nalu_type == 0x01 && xt == 0xC0){ //B幀
                    packet.pts = packet.dts + _t*2;
                }else{
                    // Error!
                    packet.pts = packet.dts;
                }

            }else{
                // Error!
            }
            
            // 將包的流索引設(shè)置為輸出流索引
            packet.stream_index = inStream->index;
            // 寫入輸出文件
            av_interleaved_write_frame(outputFormatContext, &packet);
            av_packet_unref(&packet);
            i++;
        }
        gdts_notime += p_max_dts;
        // 關(guān)閉輸入文件
        avformat_close_input(&inputFormatContext);
    }
    // 寫入文件尾部
    av_write_trailer(outputFormatContext);
    // 關(guān)閉輸出文件
    avio_close(outputFormatContext->pb);
    // 釋放資源
    avformat_free_context(outputFormatContext);
    return 0;
}

? ? ? ? 代碼中的求幀類型的方法是旁門左道且有針對性的,可能不適合其他場景。

? ? ? ?

????????對于文中任何錯誤,歡迎指正。文章來源地址http://www.zghlxwxcb.cn/news/detail-811101.html

到了這里,關(guān)于[解決思路]關(guān)于h264裸流合成mp4時時間戳添加問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • wireshark導出H264裸流

    wireshark導出H264裸流

    下載抓包工具:首先,您需要下載并安裝一個網(wǎng)絡(luò)抓包工具,例如Wireshark(https://www.wireshark.org)或tcpdump(https://www.tcpdump.org)。這些工具可用于捕獲網(wǎng)絡(luò)流量并保存為pcap或pcapng文件。在這里插入代碼片 打開抓包工具:打開所選擇的抓包工具,并啟動網(wǎng)絡(luò)監(jiān)控。 下載rtp_h264

    2024年02月15日
    瀏覽(19)
  • FFmpeg解碼H264視頻裸流(直接可用)

    1、寫在前面 此文章主要包含解碼H264視頻流數(shù)據(jù),主要有以下幾點: 1、H264視頻幀為Annex B格式,若使用AVCC格式可自行研究; 2、H264視頻裸流,非解碼視頻文件(若有需要我后期可添加這部分代碼); 3、支持輸出RGB24或YUV420格式,其他可自行修改; 4、FFmpeg官網(wǎng)代碼迭代及接口變

    2024年04月25日
    瀏覽(25)
  • 9i物聯(lián)網(wǎng)瀏覽器(cef_114.2.120&114.2.100,支持H264視頻mp3,mp4)WinForm-CefSharp(5735分支)多媒體版本體驗

    9i物聯(lián)網(wǎng)瀏覽器(cef_114.2.120&114.2.100,支持H264視頻mp3,mp4)WinForm-CefSharp(5735分支)多媒體版本體驗

    更新:2023.6.25 版本: Cef_114.2.110和114.2.100 +chromium- 114.0.5735.134 的32位和64位 說明:支持圖片,mp3,mp4(H264)多媒體 測試環(huán)境:windows server 2019(其他環(huán)境沒測,一般問題.NET4.5.2+及vc++運行庫問題) 測試網(wǎng)址:www.html5test.com 聲明 :本博是交流學習的內(nèi)容,應(yīng)用案例定制版瀏覽器

    2024年02月16日
    瀏覽(22)
  • Mp4文件提取詳細H.264和MP3文件

    要將視頻分開為H.264(視頻編碼)和MP3(音頻編碼)文件,你可以使用FFmpeg進行操作。以下是將視頻和音頻從一個視頻文件中分開并保存為H.264和MP3文件的示例命令行操作: FFmpeg安裝 這個命令將從 input.mp4 中提取視頻流并將其編碼為H.264,并將其保存為 output_video.mp4 。 -c:v li

    2024年02月09日
    瀏覽(16)
  • 關(guān)于Ubuntu python程序利用lixb264生成h264格式的視頻相關(guān)問題

    從官網(wǎng)下載:https://www.nasm.us/pub/nasm/releasebuilds/2.13.03/ 安裝包頁面上的nasm-2.13.03.tar.bz2 x264庫下載地址:http://www.videolan.org/developers/x264.html 下載 x264-master.tar.bz2 利用命令 x264 --version 查看是否配置成功 從官網(wǎng)下載ffmpeg ffmpeg-snapshot.tar.bz2 sudo ldconfig 若轉(zhuǎn)出視頻為h.264格式則說明成功

    2023年04月08日
    瀏覽(59)
  • 使用FFMPEG庫封裝264視頻和acc音頻數(shù)據(jù)到MP4文件中

    使用FFMPEG庫封裝264視頻和acc音頻數(shù)據(jù)到MP4文件中

    ffmepeg 4.4 一段H264的視頻文件 一段acc格式的音頻文件 1.使用avformat_open_input分別打開視頻和音頻文件,初始化其AVFormatContext,使用avformat_find_stream_info獲取編碼器基本信息 2.使用avformat_alloc_output_context2初始化輸出的AVFormatContext結(jié)構(gòu) 3.使用函數(shù)avformat_new_stream給輸出的AVFormatContext結(jié)

    2024年02月11日
    瀏覽(20)
  • FFmpeg從入門到入魔(3):提取MP4中的H.264和AAC

    FFmpeg從入門到入魔(3):提取MP4中的H.264和AAC

    ? ? 最近在開發(fā)中遇到了一個問題,即無法提取到MP4中H264流的關(guān)鍵幀進行處理,且保存到本地的AAC音頻也無法正常播放。經(jīng)過調(diào)試分析發(fā)現(xiàn),這是由于解封裝MP4得到的H264和AAC是ES流,它們?nèi)笔Ы獯a時必要的 起始碼 / SPS / PPS 和 adts頭 。 1. MP4格式解析 1.1 MP4簡介 ?MP4封裝格式是

    2023年04月16日
    瀏覽(16)
  • 使用FFMPEG分離mp4/flv文件中的264視頻和aac音頻

    使用FFMPEG分離mp4/flv文件中的264視頻和aac音頻

    ffmpeg 4.4 一個MP4或flv格式的視頻文件 大致分為以下幾個簡單步驟: 1.使用avformat_open_input 函數(shù)打開文件并初始化結(jié)構(gòu)AVFormatContext 2.查找是否存在音頻和視頻信息 3.構(gòu)建一個h264_mp4toannexb比特流的過濾器,用來給視頻avpaket包添加頭信息 4.打開2個輸出文件(音頻, 視頻) 5.循環(huán)讀

    2024年02月15日
    瀏覽(18)
  • OpenCV 報錯:FFMPEG: tag 0x34363258/‘X264‘ is not supported with codec id 27 and format ‘mp4 / MP4‘

    首先說一下報錯的地方,是在使用VideoWriter保存視頻時: 出現(xiàn)如下錯誤: 經(jīng)過查找網(wǎng)上資料,發(fā)現(xiàn)是cv2.VideoWriter_fourcc()參數(shù)存在問題, 解決方法: 將 修改為: 即可完美解決問題。

    2024年02月07日
    瀏覽(39)
  • 關(guān)于FFmpeg將m3u8合并成mp4之后時長不對的解決方法

    導致時長不對的合并方法 concat方法會導致合并的視頻時長有問題 時長正確的合并方法 使用讀取m3u8文件的方式合并,合并出的視頻時長是正確的。(注意:生成本地m3u8文件的時候要注意ts文件是否在下載時已經(jīng)解密。如果已經(jīng)解密,則生成的m3u8文件中不需要#EXT-X-KEY。) 參考

    2024年02月11日
    瀏覽(45)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包