基于ffmpeg编码
- 编码时要先设置基本的参数
#Create an H.264 codec
codec = av.CodecContext.create(‘h264’, ‘w’)
#Get the width and height of the frame
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#Set the codec parameters
codec.width = width
codec.height = height
codec.pix_fmt = ‘yuv420p’
-
编码器内部有状态, 送入一帧并不一定输出一个packet
# Create an AVFrame and fill it with data
av_frame = av.VideoFrame.from_ndarray(frame_rgb, format=‘rgb24’)# Encode the frame packets = codec.encode(av_frame) # Write the encoded data to the file for packet in packets: outfile.write(packet)
-
编码器的前两帧可能是PPS、SPS
这部分是解码时的依据,比如ffplay:
ffplay.exe -i D:\code\opensrc\cameracap\1.mcap.h264
调用opencv 编码jpeg
https://zhuanlan.zhihu.com/p/670334502
示例
def h264_mcap():
global cap_index
# 打开摄像头,0表示默认的摄像头
cap = cv2.VideoCapture(0)
# # Create an H.264 codec
codec = av.CodecContext.create('h264', 'w')
# Get the width and height of the frame
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
pix_fmt = 'yuv420p'
# Set the codec parameters
codec.width = width
codec.height = height
codec.pix_fmt = pix_fmt
# Open a file to write the raw H.264 data
with open(sys.argv[1], "wb") as f, Writer(f) as mcap_writer:
h264_raw = open(sys.argv[1]+".h264", "wb")
for i in range(1, 300):
ret, frame = cap.read()
current_time = int(time.time()*1000*1000*1000)
cur_sec = int(time.time())
cur_nsec = int((time.time()-cur_sec)*1000000000)
if ret:
# Convert the OpenCV BGR image to RGB
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Create an AVFrame and fill it with data
av_frame = av.VideoFrame.from_ndarray(frame_rgb, format='rgb24')
# Encode the frame
packets = codec.encode(av_frame)
# Write the encoded data to the file
for packet in packets:
if cap_index > 0:
h264_raw.write(packet)
print(f"write packet {cap_index}")
# 将编码后的帧保存为MCAP消息
video_frame = CompressedVideo(format=b'h264', frame_id="camera", timestamp=Timestamp(seconds=cur_sec,nanos=cur_nsec), data=bytes(packet))
mcap_writer.write_message(topic="/camera_h264",sequence=cap_index, message=video_frame, log_time=current_time, publish_time=current_time)
cap_index = cap_index+1
print(f"write mcap {cap_index}, video_frame: {len(video_frame.data)}")
else:
print(f"skip mcap {cap_index}")
cap_index = cap_index+1
# Display the result
cv2.imshow('frame', frame)
cv2.waitKey(10)
else:
break
current_time = int(time.time()*1000*1000*1000)
cur_sec = int(time.time())
cur_nsec = int((time.time()-cur_sec)*1000000000)
# Encode any remaining frames
for packet in codec.encode():
h264_raw.write(packet)
print(f"flush packet {cap_index}")
# 将编码后的帧保存为MCAP消息
video_frame = CompressedVideo(format=b'h264', frame_id="camera", timestamp=Timestamp(seconds=cur_sec,nanos=cur_nsec), data=bytes(packet))
mcap_writer.write_message(topic="/camera_h264",sequence=cap_index, message=video_frame, log_time=current_time, publish_time=current_time)
cap_index = cap_index+1
print(f"write mcap {cap_index}, video_frame: {len(video_frame.data)}")
cap.release()
cv2.destroyAllWindows()
h264_raw.close()
def mjpeg_mcap():
global cap_index
# 打开摄像头,0表示默认的摄像头
cap = cv2.VideoCapture(0)
# Open a file to write the raw H.264 data
with open(sys.argv[1], "wb") as f, Writer(f) as mcap_writer:
h264_raw = open(sys.argv[1]+".jpegs", "wb")
for i in range(1, 300):
ret, frame = cap.read()
current_time = int(time.time()*1000*1000*1000)
cur_sec = int(time.time())
cur_nsec = int((time.time()-cur_sec)*1000000000)
if ret:
enc_ret,enc_buf = cv2.imencode('.jpeg', frame)
if enc_ret:
h264_raw.write(enc_buf)
print(f"write packet {cap_index}")
# 将编码后的帧保存为MCAP消息
jpeg_frame = CompressedImage(format=b'image/jpeg', frame_id="camera", timestamp=Timestamp(seconds=cur_sec,nanos=cur_nsec), data=bytes(enc_buf))
mcap_writer.write_message(topic="/camera_jpeg",sequence=cap_index, message=jpeg_frame, log_time=current_time, publish_time=current_time)
cap_index = cap_index+1
print(f"write mcap {cap_index}, video_frame: {len(jpeg_frame.data)}")
# Display the result
cv2.imshow('frame', frame)
cv2.waitKey(10)
else:
break
cap.release()
cv2.destroyAllWindows()
h264_raw.close()