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

如何使用FFmpeg精確剪輯視頻

這篇具有很好參考價值的文章主要介紹了如何使用FFmpeg精確剪輯視頻。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

?1.問題描述

1.1 背景

之前基于ffmpeg做二次開發(fā),完成常見的視頻處理功能,并用ffmpeg命令行做兜底。在此基礎(chǔ)上,還做一個轉(zhuǎn)碼接入和調(diào)度系統(tǒng)對外提供服務(wù)。有個功能需要是這樣的:快速從指定的視頻中裁剪某一時間范圍的子視頻, 兩個要求:1. 要快,不能像轉(zhuǎn)碼一樣耗時;2.要精確,剪輯的時候能指定從哪一秒開始,到哪一秒結(jié)束。

1.2 難點(diǎn)

ffmpeg很容易從一個長視頻剪輯出一段小視頻。比如命令ffmpeg -i input.mp4 -ss 00:10:03 -t 00:03:00 -vcodec copy -acodec copy output.mp4就是從input.mp4的第10分鐘03秒開始剪輯出一個3分鐘的視頻并且保存為output.mp4文件。參數(shù)-vcodec copy -acodec copy就是直接拷貝原始視頻的音視頻流,不進(jìn)行編解碼。雖然上面的方法很方便,但有一個致命的缺陷:畫面在一開始會卡住(但聲音一直是正常的),幾秒后畫面才正常滾動。下面視頻是一個例子。

2.原因分析

究其原因,剪輯的開始時間落在視頻GOP的中間位置而不是第一個I幀。稍微了解過視頻編碼的同學(xué)應(yīng)該都聽過IB、P幀。簡單來說,I幀是一張完整的圖像,P幀則根據(jù)I幀做差分編碼,B幀根據(jù)前后的IP、B幀作差分編碼。也就是說I幀具有完整的內(nèi)容,而PB幀不具有,所以如果缺少I幀,那么PB幀是不能正常解碼的。通常來說,一個GOP里面第一幀是I幀,后面是若干個PB幀。一個GOP長達(dá)10秒都是有可能的。下圖是一個真實(shí)視頻的IB、P幀信息圖,紅色的表示I幀,可以看到兩個I幀相隔深遠(yuǎn)(實(shí)際是隔了10秒)。

ffmpeg視頻裁剪,ffmpeg,音視頻

從上面分析可知:剪輯的開始時間很大可能不是落在I幀,由于缺少I幀會使得后面的PB幀無法解碼導(dǎo)致畫面卡住。上面的分析都是基于不編解碼的直接拷貝視頻內(nèi)容的,如果考慮先解碼成一張張的圖像,然后再對符合時間要求的圖像編碼,那么剪輯時間可以做到非常精準(zhǔn)。但這樣做的就是耗時過長:需求花費(fèi)大量的CPU完成編解碼操作。

3.解決方案

解決的辦法還是有的:對前面第一個符合時間要求的GOP編解碼,而之后的GOP內(nèi)容則直接拷貝到目標(biāo)視頻。一來,第一個GOP的幀由于是重新編碼所以會重新分配I幀從而能播放,二來,之后的GOP內(nèi)容是直接拷貝的所以基本不消耗CPU,性能杠桿的。如下圖所示:

ffmpeg視頻裁剪,ffmpeg,音視頻

當(dāng)然這里面還是有一些坑的,下面開始填坑。

3.1 拼接

源視頻可能會驚訝:我憑本事編的碼,為什么你直接拷貝就能解碼?一般來說解碼依賴于SPSPPS,而源視頻與目標(biāo)視頻的SPSPPS會有所不同,因此直接拷貝是不能正確解碼的。對于mp4文件,SPSPPS一般是放到文件頭。一個文件只能有一個文件頭,也就不能存放兩個不同的SPSPPS。為了能正確解碼目標(biāo)視頻必須得有源視頻的SPSPPS。不能放文件頭的話,那能放哪里?能不能放到拷貝的幀的前面呢?如何放?一籌莫展、無處下手,直到有一天突然想起之前為了填一個坑,追蹤到h264_mp4toannexb的實(shí)現(xiàn),它的作用就是將SPSPPS拷貝到幀(準(zhǔn)確來說應(yīng)該是AVPacket)的前面。來!溫習(xí)一下h264_mp4toannexb的具體實(shí)現(xiàn):在所有AVPacket前面增加0x000001或者0x00000001,在I幀的前面插入SPSPPS。也就是通過h264_mp4toexannb就能把解碼所需的SPSPPS正確插入到視頻中。h264_mp4toannexb使用起來也比較簡單,代碼如下:

AVBSFContext* initBSF(const std::string &filter_name, const AVCodecParameters *codec_par, AVRational tb)
{
    const AVBitStreamFilter *filter = av_bsf_get_by_name(m_filter_name.c_str());
?
    AVBSFContext *bsf_ctx = nullptr;
    av_bsf_alloc(filter, &bsf_ctx);
?
    avcodec_parameters_copy(bsf_ctx->par_in, codec_par);
    bsf_ctx->time_base_in = tb;
?
    av_bsf_init(bsf_ctx);
    return bsf_ctx;
}
?
AVPacket* feedPacket(AVBSFContext *bsf_ctx, AVPacket &packet)
{
    av_bsf_send_packet(bsf_ctx, packet);
?
    AVPacket *dst_packet = av_packet_alloc();
    av_bsf_receive_packet(bsf_ctx, dst_packet);
?
    return dst_packet;
}
?
void test()
{
    AVBSFContext *bsf_ctx = initBSF("h264_mp4toannexb", video_stream->codecpar, video_stream->time_base);
    AVPacket *packet = readVideoPacket();
    AVPacket *dst_packet = feedPacket(bsf_ctx, packet);
}

注意:編解碼第一個GOP和原始視頻后續(xù)GOP拼接時的時間戳要小心處理,不然視頻播放時可能會出現(xiàn)抖動現(xiàn)象。

3.2 花屏

以為就完了嗎?沒有??!你會發(fā)現(xiàn)有些視頻會在最后一秒出現(xiàn)花屏。。。。

ffmpeg視頻裁剪,ffmpeg,音視頻

出現(xiàn)花屏的原因其實(shí)也不難猜到:最后一幀是B幀。由于不是所有剪輯的視頻最后一幀都是B幀,所以花屏也不是必現(xiàn)的。知道是B幀引起的,那解決方案也就明確了:保證最后一幀是P幀。即使時間上稍微超一點(diǎn)(音頻流也應(yīng)該跟著視頻流稍微超一下時間)。不過呢,由于不能直接從AVPacket判斷一個幀是否為P幀,所以最后一個GOP也得解碼(無需編碼)。記錄超出時間范圍后的第一個P幀的pts,后面拷貝GOP的時候,拷貝到這個pts就可以停止了。

4.總結(jié)

起初覺得問題很難解決,畢竟ffmpeg命令行都裁剪出來的都有問題。而萬變不離其宗,從問題的原因出發(fā),一步步尋找解決方案,并將一路上碰到的問題逐一擊破。記住,明白原理才能解決問題。

原文 如何使用FFmpeg精確剪輯視頻 - 知乎?

★文末名片可以免費(fèi)領(lǐng)取音視頻開發(fā)學(xué)習(xí)資料,內(nèi)容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音視頻學(xué)習(xí)路線圖等等。

見下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

?文章來源地址http://www.zghlxwxcb.cn/news/detail-655318.html

到了這里,關(guān)于如何使用FFmpeg精確剪輯視頻的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包