HLS公開課(七)HLS合成爲一整個視頻解決dts不連續的問題

HLS公開課(五)HLS合成爲一整個視頻 一文中講述了HLS合成爲一個MP4視頻時出現了時間戳不連續致使的合成失敗的問題.git

Application provided invalid, non monotonically increasing dts to muxer in stream 1: 11264 >= 0
複製代碼

這個問題解決了. 首先仍是要回到源碼, ffmpeg源碼中的mux.c文件======>compute_muxer_pkt_fields函數 我截取了最核心的判斷邏輯github

if (st->cur_dts && st->cur_dts != AV_NOPTS_VALUE &&
        ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) &&
          st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE &&
          st->codecpar->codec_type != AVMEDIA_TYPE_DATA &&
          st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts)) {
        av_log(s, AV_LOG_ERROR,
               "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %s >= %s\n",
               st->index, av_ts2str(st->cur_dts), av_ts2str(pkt->dts));
        return AVERROR(EINVAL);
    }
複製代碼

如今咱們一個一個拆解一下判斷邏輯:markdown

  • 條件一:

st->cur_dts 說明當前的dts要存在,並且要大於0ide

  • 條件二:

st->cur_dts != AV_NOPTS_VALUE 說明當前dts必定不能未知, 不能等於AV_NOPTS_VALUE #define AV_NOPTS_VALUE ((int64_t)UINT64_C(0x8000000000000000))函數

  • 條件三:

((!(s->oformat->flags & AVFMT_TS_NONSTRICT) && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE && st->codecpar->codec_type != AVMEDIA_TYPE_DATA && st->cur_dts >= pkt->dts) 條件三比較複雜, 而且都是&&, 說明只要有一個條件不成立, 整個條件都不成立.oop

  • 條件四:

st->cur_dts > pkt->dts 當前的dts必定要大於avpacket中的dts, 這樣的條件未免有點苛刻了.post

條件三是有必要拿出來說講的, !(s->oformat->flags & AVFMT_TS_NONSTRICT) s->oformat->flags是一個枚舉的標記, 表示當前從新封裝的視頻遵照什麼規則ui

/// Demuxer will use avio_open, no opened file should be provided by the caller.
#define AVFMT_NOFILE        0x0001
#define AVFMT_NEEDNUMBER    0x0002 /**< Needs '%d' in filename. */
#define AVFMT_SHOW_IDS      0x0008 /**< Show format stream IDs numbers. */
#define AVFMT_GLOBALHEADER  0x0040 /**< Format wants global header. */
#define AVFMT_NOTIMESTAMPS  0x0080 /**< Format does not need / have any timestamps. */
#define AVFMT_GENERIC_INDEX 0x0100 /**< Use generic index building code. */
#define AVFMT_TS_DISCONT    0x0200 /**< Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps */
#define AVFMT_VARIABLE_FPS  0x0400 /**< Format allows variable fps. */
#define AVFMT_NODIMENSIONS  0x0800 /**< Format does not need width/height */
#define AVFMT_NOSTREAMS     0x1000 /**< Format does not require any streams */
#define AVFMT_NOBINSEARCH   0x2000 /**< Format does not allow to fall back on binary search via read_timestamp */
#define AVFMT_NOGENSEARCH   0x4000 /**< Format does not allow to fall back on generic search */
#define AVFMT_NO_BYTE_SEEK  0x8000 /**< Format does not allow seeking by bytes */
#define AVFMT_ALLOW_FLUSH  0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */
#define AVFMT_TS_NONSTRICT 0x20000 /**< Format does not require strictly
                                        increasing timestamps, but they must
                                        still be monotonic */
#define AVFMT_TS_NEGATIVE  0x40000 /**< Format allows muxing negative
                                        timestamps. If not set the timestamp
                                        will be shifted in av_write_frame and
                                        av_interleaved_write_frame so they
                                        start from 0.
                                        The user or muxer can override this through
                                        AVFormatContext.avoid_negative_ts
                                        */

#define AVFMT_SEEK_TO_PTS   0x4000000 /**< Seeking is based on PTS */
複製代碼

s->oformat->flags & AVFMT_TS_NONSTRICT 表示輸出的視頻format格式已經設置了非嚴格遞增的時間戳, 這一點很重要, 咱們在HLS合成MP4以前, 須要設置這一參數, 而後s->oformat->flags & AVFMT_TS_NONSTRICT 結果爲true, !(s->oformat->flags & AVFMT_TS_NONSTRICT)爲false, 條件三天然就不成立.this

條件四的判斷我以爲有點雞肋, 由於已經不要dts是嚴格遞增了, 爲何還要加這個判斷了, 個人策略是直接去掉這個判斷. 因此我將ffmpeg中源碼的最終判斷條件該成以下:spa

if (st->cur_dts && st->cur_dts != AV_NOPTS_VALUE &&
        ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) &&
          st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE &&
          st->codecpar->codec_type != AVMEDIA_TYPE_DATA &&
          st->cur_dts >= pkt->dts))) {
        av_log(s, AV_LOG_ERROR,
               "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %s >= %s\n",
               st->index, av_ts2str(st->cur_dts), av_ts2str(pkt->dts));
        return AVERROR(EINVAL);
    }
複製代碼

並且我在demo中還加上dts和pts的嚴格校驗代碼, 核心思想就是保證pts或者dts不能出現AV_NOPTS_VALUE

if (pkt.pts == AV_NOPTS_VALUE) {
            if (pkt.dts != AV_NOPTS_VALUE) {
                pkt.pts = pkt.dts;
                last_dts = pkt.dts;
            } else {
                pkt.pts = last_dts + 1;
                pkt.dts = pkt.pts;
                last_dts = pkt.pts;
            }
        } else {
            if (pkt.dts != AV_NOPTS_VALUE) {
                last_dts = pkt.dts;
            } else {
                pkt.dts = pkt.pts;
                last_dts = pkt.dts;
            }
        }

        if (pkt.pts < pkt.dts) {
            pkt.pts = pkt.dts;
        }
複製代碼

源視頻以下:

PD1824:/sdcard/下載/.video-cache/481b863cc1d8ac51b3c3dd1a6f82cc3d # ls
481b863cc1d8ac51b3c3dd1a6f82cc3d.m3u8 video_1.ts  video_14.ts video_19.ts video_23.ts video_28.ts video_32.ts video_37.ts video_41.ts video_46.ts video_50.ts video_9.ts 
remote.m3u8                           video_10.ts video_15.ts video_2.ts  video_24.ts video_29.ts video_33.ts video_38.ts video_42.ts video_47.ts video_51.ts 
ts_video.info                         video_11.ts video_16.ts video_20.ts video_25.ts video_3.ts  video_34.ts video_39.ts video_43.ts video_48.ts video_6.ts  
video.info                            video_12.ts video_17.ts video_21.ts video_26.ts video_30.ts video_35.ts video_4.ts  video_44.ts video_49.ts video_7.ts  
video_0.ts                            video_13.ts video_18.ts video_22.ts video_27.ts video_31.ts video_36.ts video_40.ts video_45.ts video_5.ts  video_8.ts
複製代碼

執行後獲得test.mp4:

PD1824:/sdcard/下載/.video-cache/481b863cc1d8ac51b3c3dd1a6f82cc3d # ls -hl test.mp4                                                                                                                          
-rw-rw---- 1 root sdcard_rw 40M 2021-03-29 15:35 test.mp4
複製代碼

具體見: github.com/JeffMony/Je… github.com/JeffMony/Vi…

相關文章
相關標籤/搜索