incoming video yuv => bgr fix

This commit is contained in:
ingvar1995 2017-06-13 21:14:05 +03:00
parent c60808a7da
commit 464fba23c5
2 changed files with 67 additions and 9 deletions

View File

@ -324,21 +324,50 @@ def callback_audio(toxav, friend_number, samples, audio_samples_per_channel, aud
def video_receive_frame(toxav, friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data): def video_receive_frame(toxav, friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data):
"""
Creates yuv frame from y, u, v and shows it using OpenCV
For yuv => bgr we need this YUV420 frame:
width
-------------------------
| |
| Y | height
| |
-------------------------
| | |
| U even | U odd | height // 4
| | |
-------------------------
| | |
| V even | V odd | height // 4
| | |
-------------------------
width // 2 width // 2
It can be created from initial y, u, v using slices
For more info see callback_video_receive_frame docs
"""
try: try:
y_size = abs(max(width, abs(ystride))) y_size = abs(max(width, abs(ystride)))
u_size = abs(max(width//2, abs(ustride))) u_size = abs(max(width // 2, abs(ustride)))
v_size = abs(max(width//2, abs(vstride))) v_size = abs(max(width // 2, abs(vstride)))
y = np.asarray(y[:y_size * height], dtype=np.uint8).reshape(height, y_size) y = np.asarray(y[:y_size * height], dtype=np.uint8).reshape(height, y_size)
u = np.asarray(u[:u_size * height // 2], dtype=np.uint8).reshape(height // 2, u_size) u = np.asarray(u[:u_size * height // 2], dtype=np.uint8).reshape(height // 2, u_size)
v = np.asarray(v[:v_size * height // 2], dtype=np.uint8).reshape(height // 2, v_size) v = np.asarray(v[:v_size * height // 2], dtype=np.uint8).reshape(height // 2, v_size)
width -= width % 4
height -= height % 4
frame = np.zeros((int(height * 1.5), width), dtype=np.uint8) frame = np.zeros((int(height * 1.5), width), dtype=np.uint8)
frame[:height, :] = y[:, :width] frame[:height, :] = y[:height, :width]
frame[height:height * 5 // 4, :width // 2] = u[:140:2, :width // 2] # TODO: remove hardcoded values frame[height:height * 5 // 4, :width // 2] = u[:height // 2:2, :width // 2]
frame[height:height * 5 // 4, width // 2:] = u[1:140:2, :width // 2] frame[height:height * 5 // 4, width // 2:] = u[1:height // 2:2, :width // 2]
frame[height * 5 // 4 + 1:, :width // 2] = v[:140:2, :width // 2] frame[height * 5 // 4:, :width // 2] = v[:height // 2:2, :width // 2]
frame[height * 5 // 4 + 1:, width // 2:] = v[1:140:2, :width // 2] frame[height * 5 // 4:, width // 2:] = v[1:height // 2:2, :width // 2]
frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420)
@ -382,4 +411,3 @@ def init_callbacks(tox, window, tray):
tox.callback_friend_lossless_packet(lossless_packet, 0) tox.callback_friend_lossless_packet(lossless_packet, 0)
tox.callback_friend_lossy_packet(lossy_packet, 0) tox.callback_friend_lossy_packet(lossy_packet, 0)

View File

@ -217,7 +217,37 @@ class AV:
time.sleep(0.01) time.sleep(0.01)
def convert_bgr_to_yuv(frame): # TODO: remove hardcoded values and add docs def convert_bgr_to_yuv(frame): # TODO: remove hardcoded values
"""
:param frame: input bgr frame
:return y, u, v: y, u, v values of frame
How this function works:
OpenCV creates YUV420 frame from BGR
This frame has following structure and size:
width, height - dim of input frame
width, height * 1.5 - dim of output frame
width
-------------------------
| |
| Y | height
| |
-------------------------
| | |
| U even | U odd | height // 4
| | |
-------------------------
| | |
| V even | V odd | height // 4
| | |
-------------------------
width // 2 width // 2
Y, U, V can be extracted using slices and joined in one list using itertools.chain.from_iterable()
Function returns bytes(y), bytes(u), bytes(v), because it is required for ctypes
"""
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420) frame = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420)
y = frame[:480, :].tolist() y = frame[:480, :].tolist()