使用Python實現視頻拼接效果
更新時間:2025年02月07日 16:10:56 作者:AI算法網奇
這篇文章主要為大家詳細介紹了使用Python實現視頻拼接效果的兩種方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
方法一:
視頻較長,分辨率較大,這個效果很好,不耗用內存 ffmpeg
import subprocess
import glob
import os
from natsort import natsorted
base_dir = r'C:\Users\Administrator\Videos\shuiyin\result'
output_file = r'output_shuiyin.mp4'
video_paths = glob.glob(base_dir + '/*.mp4')
video_paths = natsorted(video_paths)
with open('file_list.txt', 'w') as f:
for file in video_paths:
f.write(f"file '{file}'\n")
ffmpeg_command = [
'ffmpeg',
'-f', 'concat', # 指定拼接模式
'-safe', '0', # 允許絕對路徑
'-i', 'file_list.txt', # 輸入的文件列表
'-c:v', 'libx264', # 使用 libx264 編碼器
'-c:a', 'aac', # 使用 aac 編碼音頻
'-strict', 'experimental',# 使用實驗性編碼
output_file # 輸出文件路徑
]
subprocess.run(ffmpeg_command, check=True)
print(f"視頻拼接完成,輸出文件:{output_file}")方法二:
利用imageio,適合視頻較短
import glob
from natsort import natsorted
from moviepy.editor import VideoFileClip, concatenate_videoclips
import glob
import os.path
from natsort import natsorted
import cv2
import imageio
if __name__ == '__main__':
#內存
base_dir =r"C:\Users\Administrator\Videos\shuiyin\0127"
base_dir =r'C:\Users\Administrator\Videos\shuiyin\result'
output_path = "pinjie_shuiyin.mp4"
video_paths =glob.glob(base_dir +'/*.mp4')
video_paths=natsorted(video_paths)
imgs=[]
res = []
for file in video_paths:
cap_a = cv2.VideoCapture(file) # 打開視頻B
fps = cap_a.get(cv2.CAP_PROP_FPS)
frame_count = 0
print(file)
while True:
ret, frame_a = cap_a.read()
if not ret:
break # 如果沒有讀取到幀,則跳出循環(huán)
res.append(cv2.cvtColor(frame_a, cv2.COLOR_BGR2RGB))
frame_count += 1 # 釋放視頻資源
cap_a.release()
imageio.mimsave(output_path, res, "mp4", fps=fps, macro_block_size=None)
方法三:
使用FFmpeg進行視頻拼接,主要以兩個文件為例進行合并,并且只轉換其中的視頻流
vector<string> fileList = { url_origin,url_add };//這是兩個文件
//獲得原始輸入視頻文件編碼等信息
const AVOutputFormat* ofmt = NULL;//輸出格式
AVFormatContext* ifmt_ctx = NULL, * ofmt_ctx = NULL;//視頻數據維護對象
AVPacket* pkt = NULL;//數據包
int ret;//函數執(zhí)行返回碼
int stream_index;//數據流索引
pkt = av_packet_alloc();//初始化數據包結構
if (!pkt)
{
return;
}
if ((ret = avformat_open_input(&ifmt_ctx, url_origin, 0, 0) < 0))
{
goto end;//打開文件失敗
}
//獲得輸出文件名
string out_file;
auto name = ifmt_ctx->iformat->name;//自動識別文件的封裝類型
//hevc只能使用MP4或者hevc封裝才能完成轉換,其余封裝報錯,因為這里進行了自動識別可以不用管具體格式
out_file.replace(out_file.find('.')+1, 3, name);
const char* out_filename = out_file.c_str();
//根據第一個文件獲得其中的編碼等參數,這里要求兩個文件的編碼格式一樣就是因為在寫入文件時用的是相同的配置沒有進行轉碼等操作
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0)
{
goto end;
}
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx)
{
goto end;
}
ofmt = ofmt_ctx->oformat;
//查找視頻流并復制視頻流的參數到輸出流
for (int i = 0; i < ifmt_ctx->nb_streams; ++i)
{
AVStream* in_stream = ifmt_ctx->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO)//非視頻流跳過
{
continue;
}
AVStream* out_stream = avformat_new_stream(ofmt_ctx, NULL);//創(chuàng)建輸出流
if (!out_stream)
{
goto end;
}
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);//復制解碼器參數
if (ret < 0)
{
goto end;
}
out_stream->time_base = in_stream->time_base;//復制時間基
stream_index = i;
out_stream->codecpar->codec_tag = 0;
break;
}
avformat_close_input(&ifmt_ctx);//關閉文件
//打開輸出文件
if (!(ofmt->flags & AVFMT_NOFILE))
{
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0)
{
goto end;
}
}
ret = avformat_write_header(ofmt_ctx, NULL);//寫入頭信息,如編碼等內容
if (ret < 0)
{
goto end;
}
int64_t i = 0;//用于計算時間戳,同時也是幀數
int64_t p_max_dts = 0;//用于拼文件的時間戳
for (int index = 0; index < fileList.size(); ++index)//遍歷文件
{
if ((ret = avformat_open_input(&ifmt_ctx, fileList[index].c_str(), 0, 0)) < 0)
{
goto end;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0)//查找文件流信息
{
goto end;
}
//對流直接進行轉寫
while (1)
{
AVStream* in_stream, * out_stream;
ret = av_read_frame(ifmt_ctx, pkt);
if (ret < 0)
{
break;
}
pkt->stream_index = stream_index;//視頻流編號
//這里做一個提示,因為上述的例子只有視頻沒有音頻所以不會越界,如果存在多種流的這里需要看一下你new了幾個流,是否會越界
in_stream = ifmt_ctx->streams[stream_index];
out_stream = ofmt_ctx->streams[stream_index];
//這里要對時間戳進行處理,否則寫入的時候會失敗
//單幀時長
int64_t frameDuration = av_rescale_q(1, av_inv_q(in_stream->time_base), in_stream->r_frame_rate);
//將單幀的時間從輸入流轉化到輸出流時間
int64_t _t = av_rescale_q(frameDuration, in_stream->time_base, out_stream->time_base);
//計算時間戳,并進行累計以推算后面的時間戳
p_max_dts = _t * (i);
pkt->dts = p_max_dts;
pkt->pts = pkt->dts;
//如果音視頻都需要寫入可能需要這個函數:av_interleaved_write_frame,他會進行交叉寫入
//pkt現在是空的,這個函數會獲得pkt內容的所有權并重置,因此不需要unref,但是write_frame情況不同,需要手動釋放
ret = av_write_frame(ofmt_ctx, pkt);//直接將包寫入輸出文件不進行解碼
av_packet_unref(pkt);
if (ret < 0)
{
break;
}
++i;
}
//關閉文件
avformat_close_input(&ifmt_ctx);
}
av_write_trailer(ofmt_ctx);//寫文件尾
end:
av_packet_free(&pkt);//這里傳指針,因為要將pkt設為null
avformat_close_input(&ifmt_ctx);//同理
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
{
avio_closep(&ofmt_ctx->pb);//avio打開要釋放
}
avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != AVERROR_EOF)
{
return;//異常結束
}
這個示例可以完成視頻流的復制拼接,是一個比較簡單的示例,要求文件編碼等信息必須一致,不進行轉碼,速度比較快。
到此這篇關于使用Python實現視頻拼接效果的文章就介紹到這了,更多相關Python視頻拼接內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python標準庫中內置裝飾器@staticmethod和@classmethod
裝飾器是Python中強大而靈活的功能,用于修改或增強函數或方法的行為,本文就來介紹一下Python標準庫中內置裝飾器@staticmethod和@classmethod,感興趣的可以了解一下2023-10-10

