Your Code
# coding:utf-8
import time
import acl
import cv2
import numpy as np
import subprocess
def t_g(frame):
# 获取图像的高、宽
height, width, _ = frame.shape
# 将 BGR 图像转换为 YUV 格式
yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV)
# 创建一个大小为 height + height//2 和 width 的空数组来存储 YUV420SP (NV12) 格式
yuv420sp = np.zeros((height + height // 2, width), dtype=np.uint8)
# Y 分量:直接将 Y 分量拷贝到 yuv420sp 中
yuv420sp[:height, :] = yuv[:, :, 0]
# UV 分量(NV12格式,U和V交替排列)
u = yuv[:, :, 1]
v = yuv[:, :, 2]
# 将 U 和 V 分量合并为一个交替存储的格式(NV12:U和V交替)
yuv420sp[height:, ::2] = u[::2, ::2] # U 分量
yuv420sp[height:, 1::2] = v[::2, ::2] # V 分量
return yuv420sp
memcpy_kind = {
"ACL_MEMCPY_HOST_TO_HOST": 0,
"ACL_MEMCPY_HOST_TO_DEVICE": 1,
"ACL_MEMCPY_DEVICE_TO_HOST": 2,
"ACL_MEMCPY_DEVICE_TO_DEVICE": 3
}
# 1. pyACL 初始化
ret = acl.init()
acl.rt.set_device(0)
# 2. 获取软件栈的运行模式
run_mode, ret = acl.rt.get_run_mode()
print(f"run_mode is >>>>>>>>> {run_mode},ret >>>>>>>>>>> {ret}")
# 3. 运行管理资源申请
# 4. 初始化媒体数据处理系统
ret = acl.himpi.sys_init()
# 5. 设置 VENC 模块参数
param = {'mod_type': 2 , # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0651.html
'h264_mod_param':{ # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0653.html
"one_stream_buf":1,
"mini_buf_mode":1,
"low_power_mode":1,
"vb_src":2,
"qp_hist_en":1,
"max_user_data_len":1024
}
}
param, ret = acl.himpi.venc_get_mod_param(param)
# param['jpeg_mod_param']['one_stream_buf'] = 1
ret = acl.himpi.venc_set_mod_param(param)
# 6. 创建编码通道
channel_id = 0
venc_attr = {
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0616.html
'type': 96,
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0562.html
'profile': 0,
'max_pic_width': 1280,
'pic_width': 1280,
'max_pic_height': 720,
'pic_height': 720,
'buf_size': 5 * 1024 * 720,
'is_by_frame': 1,
"h264_attr": {
"rcn_ref_share_buf_en": 0,
"frame_buf_ratio": 80
}
}
rc_attr = {
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0617.html
'rc_mode': 2,
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0618.html
'h264_vbr': # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0619.html
{'gop': 30, 'stats_time': 1, 'src_frame_rate': 30, 'dst_frame_rate': 30, 'max_bit_rate': 2000}
}
gop_attr = {'gop_mode': 0, 'normal_p': {'ip_qp_delta': -1}}
attr = {'venc_attr': venc_attr, 'rc_attr': rc_attr, 'gop_attr': gop_attr}
ret = acl.himpi.venc_create_chn(channel_id, attr)
# 7. 通知编码器开始接收输入数据
recv_param = {'recv_pic_num': -1}
ret = acl.himpi.venc_start_chn(channel_id, recv_param)
print('[INFO] venc_start_chn', ret)
# 8. 设置 RTSP 推流
# rtsp_url = "rtsp://127.0.0.1:8554/video"
# ffmpeg_process = subprocess.Popen([
# "ffmpeg",
# "-y", "-f", "rawvideo",
# "-pix_fmt", "yuv420p",
# "-s", "1280x720",
# "-i", "-",
# "-c:v", "libx264",
# "-f", "rtsp",
# rtsp_url
# ], stdin=subprocess.PIPE)
# 9. 捕获摄像头帧并编码推流
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
cap.set(cv2.CAP_PROP_FPS, 30)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc(*"MJPG")) # 设置宽度
cap.set(cv2.CAP_PROP_FPS, 120)
cap.set(cv2.CAP_PROP_AUTO_WB, 1.0) # 打开自动白平衡
for i in range(40):
cap.read()
time.sleep(1000 / 25 / 1000) # 目的是为了清掉相机里白平衡的数据?
cap.set(cv2.CAP_PROP_GAIN, 255)
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0) # 打开自动曝光 (相机会记住曝光)
fd = acl.himpi.venc_get_fd(channel_id)
# epoll_fd, ret = acl.himpi.sys_create_epoll(10)
# print('[INFO] sys_create_epoll', ret)
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0577.html
# event = {'data': fd, 'events': 1}
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0576.html
# ret = acl.himpi.sys_ctl_epoll(epoll_fd, 1, fd, event)
# print('[INFO] sys_ctl_epoll', ret)
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0421.html
while True:
ret, frame = cap.read()
if not ret:
break
print('[DEBUG] Frame shape:', frame.shape)
# 转换为 YUV420 格式
frame_yuv = t_g(frame)
input_size = frame_yuv.nbytes
input_addr, ret = acl.himpi.dvpp_malloc(0, input_size)
bytes_data = frame_yuv.tobytes()
frame_ptr = acl.util.bytes_to_ptr(bytes_data)
# acl.rt.get_run_mode接口获取软件栈的运行模式为ACL_DEVICE,则直接申请Device内存,存放输入图片数据
ret = acl.rt.memcpy(input_addr, input_size, frame_ptr, input_size, memcpy_kind['ACL_MEMCPY_DEVICE_TO_DEVICE'])
# 创建编码帧结构
v_frame = {
'width': 1280, 'height': 720,
'field': 0x4,
# https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgp/aclpythondevg_01_0549.html
'pixel_format': 1,
# https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgc/aclcppdevg_03_1093.html
'video_format': 0,
# https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgc/aclcppdevg_03_1104.html
'compress_mode': 0,
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclcppdevg_03_0804.html
'dynamic_range': 0,
# https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclcppdevg_03_0777.html
'color_gamut': 1,
# https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgp/aclpythondevg_01_0551.html
'width_stride': [1280, 0, 0],
'virt_addr': [input_addr, 0, 0],
'header_stride': [0, 0, 0],
'height_stride': [0, 0, 0],
'header_phys_addr': [0, 0, 0],
'phys_addr': [0, 0, 0],
'header_virt_addr': [0, 0, 0],
'time_ref': 0, 'pts': 123
}
frame = {'v_frame': v_frame, 'pool_id': 0,
'mod_id': 10} # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/developmentguide/appdevg/ispdevug/ispdevapi_0031.html
ret = acl.himpi.venc_send_frame(channel_id, frame, -1)
# print('[INFO] venc_send_frame', ret)
# time.sleep(5)
# events, eventCount, ret = acl.himpi.sys_wait_epoll(epoll_fd, 3, 1000)
# 获取编码结果
# print('[INFO] sys_create_epoll', ret,events,eventCount)
status, ret = acl.himpi.venc_query_status(channel_id)
print('[INFO] venc_query_status', ret, status)
# 获取编码结果
if status['cur_packs'] > 0:
stream = {'pack_cnt': status['cur_packs']}
stream, ret = acl.himpi.venc_get_stream(channel_id, stream, 1000)
if ret == 0:
print('[INFO] venc_get_stream success')
encoded_data = acl.util.ptr_to_bytes(stream['pack'][0]['addr'])
# ffmpeg_process.stdin.write(encoded_data)
ret = acl.himpi.venc_release_stream(channel_id, stream)
else:
print('[ERROR] venc_get_stream failed:', ret)
else:
print('[DEBUG] No data available in cur_packs')
# print('[INFO] venc_query_status', ret, status)
# stream = {'pack_cnt': status['cur_packs']}
# stream, ret = acl.himpi.venc_get_stream(channel_id, stream, 1000)
# print('[INFO] venc_get_stream', ret)
# encoded_data = acl.util.ptr_to_bytes(stream['pack'][0]['addr'])
# ffmpeg_process.stdin.write(encoded_data)
# ret = acl.himpi.venc_release_stream(channel_id, stream)
# 10. 释放资源
cap.release()
# ffmpeg_process.stdin.close()
# ffmpeg_process.wait()
ret = acl.himpi.venc_stop_chn(channel_id)
ret = acl.himpi.venc_destroy_chn(channel_id)
ret = acl.himpi.sys_exit()
ret = acl.finalize()
Your Code # coding:utf-8 import time import acl import cv2 import numpy as np import subprocess def t_g(frame): # 获取图像的高、宽 height, width, _ = frame.shape # 将 BGR 图像转换为 YUV 格式 yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV) # 创建一个大小为 height + height//2 和 width 的空数组来存储 YUV420SP (NV12) 格式 yuv420sp = np.zeros((height + height // 2, width), dtype=np.uint8) # Y 分量:直接将 Y 分量拷贝到 yuv420sp 中 yuv420sp[:height, :] = yuv[:, :, 0] # UV 分量(NV12格式,U和V交替排列) u = yuv[:, :, 1] v = yuv[:, :, 2] # 将 U 和 V 分量合并为一个交替存储的格式(NV12:U和V交替) yuv420sp[height:, ::2] = u[::2, ::2] # U 分量 yuv420sp[height:, 1::2] = v[::2, ::2] # V 分量 return yuv420sp memcpy_kind = { "ACL_MEMCPY_HOST_TO_HOST": 0, "ACL_MEMCPY_HOST_TO_DEVICE": 1, "ACL_MEMCPY_DEVICE_TO_HOST": 2, "ACL_MEMCPY_DEVICE_TO_DEVICE": 3 } # 1. pyACL 初始化 ret = acl.init() acl.rt.set_device(0) # 2. 获取软件栈的运行模式 run_mode, ret = acl.rt.get_run_mode() print(f"run_mode is >>>>>>>>> {run_mode},ret >>>>>>>>>>> {ret}") # 3. 运行管理资源申请 # 4. 初始化媒体数据处理系统 ret = acl.himpi.sys_init() # 5. 设置 VENC 模块参数 param = {'mod_type': 2 , # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0651.html 'h264_mod_param':{ # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0653.html "one_stream_buf":1, "mini_buf_mode":1, "low_power_mode":1, "vb_src":2, "qp_hist_en":1, "max_user_data_len":1024 } } param, ret = acl.himpi.venc_get_mod_param(param) # param['jpeg_mod_param']['one_stream_buf'] = 1 ret = acl.himpi.venc_set_mod_param(param) # 6. 创建编码通道 channel_id = 0 venc_attr = { # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0616.html 'type': 96, # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0562.html 'profile': 0, 'max_pic_width': 1280, 'pic_width': 1280, 'max_pic_height': 720, 'pic_height': 720, 'buf_size': 5 * 1024 * 720, 'is_by_frame': 1, "h264_attr": { "rcn_ref_share_buf_en": 0, "frame_buf_ratio": 80 } } rc_attr = { # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0617.html 'rc_mode': 2, # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0618.html 'h264_vbr': # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0619.html {'gop': 30, 'stats_time': 1, 'src_frame_rate': 30, 'dst_frame_rate': 30, 'max_bit_rate': 2000} } gop_attr = {'gop_mode': 0, 'normal_p': {'ip_qp_delta': -1}} attr = {'venc_attr': venc_attr, 'rc_attr': rc_attr, 'gop_attr': gop_attr} ret = acl.himpi.venc_create_chn(channel_id, attr) # 7. 通知编码器开始接收输入数据 recv_param = {'recv_pic_num': -1} ret = acl.himpi.venc_start_chn(channel_id, recv_param) print('[INFO] venc_start_chn', ret) # 8. 设置 RTSP 推流 # rtsp_url = "rtsp://127.0.0.1:8554/video" # ffmpeg_process = subprocess.Popen([ # "ffmpeg", # "-y", "-f", "rawvideo", # "-pix_fmt", "yuv420p", # "-s", "1280x720", # "-i", "-", # "-c:v", "libx264", # "-f", "rtsp", # rtsp_url # ], stdin=subprocess.PIPE) # 9. 捕获摄像头帧并编码推流 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) cap.set(cv2.CAP_PROP_FPS, 30) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc(*"MJPG")) # 设置宽度 cap.set(cv2.CAP_PROP_FPS, 120) cap.set(cv2.CAP_PROP_AUTO_WB, 1.0) # 打开自动白平衡 for i in range(40): cap.read() time.sleep(1000 / 25 / 1000) # 目的是为了清掉相机里白平衡的数据? cap.set(cv2.CAP_PROP_GAIN, 255) cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0) # 打开自动曝光 (相机会记住曝光) fd = acl.himpi.venc_get_fd(channel_id) # epoll_fd, ret = acl.himpi.sys_create_epoll(10) # print('[INFO] sys_create_epoll', ret) # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0577.html # event = {'data': fd, 'events': 1} # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0576.html # ret = acl.himpi.sys_ctl_epoll(epoll_fd, 1, fd, event) # print('[INFO] sys_ctl_epoll', ret) # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclpythondevg_01_0421.html while True: ret, frame = cap.read() if not ret: break print('[DEBUG] Frame shape:', frame.shape) # 转换为 YUV420 格式 frame_yuv = t_g(frame) input_size = frame_yuv.nbytes input_addr, ret = acl.himpi.dvpp_malloc(0, input_size) bytes_data = frame_yuv.tobytes() frame_ptr = acl.util.bytes_to_ptr(bytes_data) # acl.rt.get_run_mode接口获取软件栈的运行模式为ACL_DEVICE,则直接申请Device内存,存放输入图片数据 ret = acl.rt.memcpy(input_addr, input_size, frame_ptr, input_size, memcpy_kind['ACL_MEMCPY_DEVICE_TO_DEVICE']) # 创建编码帧结构 v_frame = { 'width': 1280, 'height': 720, 'field': 0x4, # https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgp/aclpythondevg_01_0549.html 'pixel_format': 1, # https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgc/aclcppdevg_03_1093.html 'video_format': 0, # https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgc/aclcppdevg_03_1104.html 'compress_mode': 0, # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclcppdevg_03_0804.html 'dynamic_range': 0, # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/apiref/appdevgapi/aclcppdevg_03_0777.html 'color_gamut': 1, # https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application%20Development%20Guide/aadgp/aclpythondevg_01_0551.html 'width_stride': [1280, 0, 0], 'virt_addr': [input_addr, 0, 0], 'header_stride': [0, 0, 0], 'height_stride': [0, 0, 0], 'header_phys_addr': [0, 0, 0], 'phys_addr': [0, 0, 0], 'header_virt_addr': [0, 0, 0], 'time_ref': 0, 'pts': 123 } frame = {'v_frame': v_frame, 'pool_id': 0, 'mod_id': 10} # https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/developmentguide/appdevg/ispdevug/ispdevapi_0031.html ret = acl.himpi.venc_send_frame(channel_id, frame, -1) # print('[INFO] venc_send_frame', ret) # time.sleep(5) # events, eventCount, ret = acl.himpi.sys_wait_epoll(epoll_fd, 3, 1000) # 获取编码结果 # print('[INFO] sys_create_epoll', ret,events,eventCount) status, ret = acl.himpi.venc_query_status(channel_id) print('[INFO] venc_query_status', ret, status) # 获取编码结果 if status['cur_packs'] > 0: stream = {'pack_cnt': status['cur_packs']} stream, ret = acl.himpi.venc_get_stream(channel_id, stream, 1000) if ret == 0: print('[INFO] venc_get_stream success') encoded_data = acl.util.ptr_to_bytes(stream['pack'][0]['addr']) # ffmpeg_process.stdin.write(encoded_data) ret = acl.himpi.venc_release_stream(channel_id, stream) else: print('[ERROR] venc_get_stream failed:', ret) else: print('[DEBUG] No data available in cur_packs') # print('[INFO] venc_query_status', ret, status) # stream = {'pack_cnt': status['cur_packs']} # stream, ret = acl.himpi.venc_get_stream(channel_id, stream, 1000) # print('[INFO] venc_get_stream', ret) # encoded_data = acl.util.ptr_to_bytes(stream['pack'][0]['addr']) # ffmpeg_process.stdin.write(encoded_data) # ret = acl.himpi.venc_release_stream(channel_id, stream) # 10. 释放资源 cap.release() # ffmpeg_process.stdin.close() # ffmpeg_process.wait() ret = acl.himpi.venc_stop_chn(channel_id) ret = acl.himpi.venc_destroy_chn(channel_id) ret = acl.himpi.sys_exit() ret = acl.finalize()