1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <linux/videodev2.h> 20 #include <iostream> 21 #include "common/libs/fs/shared_fd.h" 22 #include "common/libs/utils/result.h" 23 #include "utils/Timers.h" 24 #include "vsock_connection.h" 25 26 namespace cuttlefish { 27 28 // VsockFrameSource accepts WebRTC YUV camera stream data 29 // over vsock, converts it to v4l2 format BGRX32, and then 30 // writes the result to a v4l2 device. This allows for creation 31 // of v4l2 devices in guest VMs, and streaming to them 32 // from Cuttlefish's WebRTC UI via any connected camera. 33 class VsockFrameSource { 34 public: 35 // Starts a Frame Source streaming session targeting a 36 // specific v4l2 device 37 static Result<std::unique_ptr<VsockFrameSource>> Start( 38 const std::string& v4l2_device_path); 39 40 ~VsockFrameSource(); 41 42 // Stops a thread managing the stream if running, and closes the v4l2 device. 43 void Stop(); 44 45 // Returns true if there is a camera stream currently running 46 bool Running(); 47 48 // This is a blocking method, that runs while connection is valid. 49 // It receives frames from a vsock socket, formats the data stream and 50 // sends it to a v4l2 output device. 51 void VsockReadLoop(); 52 53 // Starts a Thread which invokes VsockReadLoop(). This allows the calling 54 // thread to perform other operations while this frame source is sending data. 55 Result<void> VsockReadLoopThreaded(); 56 57 private: 58 // The v4l2 device path to receive camera frames, ie /dev/video0 59 std::string v4l2_device_path_; 60 std::unique_ptr<cuttlefish::VsockConnection> connection_; 61 std::thread reader_thread_; 62 std::atomic<bool> running_; 63 std::mutex frame_mutex_; 64 std::mutex settings_mutex_; 65 std::atomic<nsecs_t> timestamp_; 66 std::condition_variable yuv_frame_updated_; 67 68 // File handle of v4l2 device to be written to 69 SharedFD fd_v4l2_device_; 70 71 // Following frame_* values will be set after successful connection. 72 // Host process sends a message which conveys the camera dimensions 73 // to this guest instance over the vsock connection. 74 int frame_width_ = 0; 75 int frame_height_ = 0; 76 int frame_rate_ = 0; 77 int frame_size_ = 0; 78 79 // Currently this class only supports writing to v4l2 devices 80 // via this format. 81 int format_ = V4L2_PIX_FMT_BGRX32; 82 83 // Verifies that given data is a video frame. Used to 84 // distinguish control messages. 85 bool FramesizeMatches(const std::vector<char>& data); 86 87 // Determines if a vsock packet contains special data 88 // that is not camera frame. 89 bool IsBlob(const std::vector<char>& blob); 90 91 // Sends message to Host process communicating an event in the 92 // camera connection state. ie - when to start or stop streaming. 93 bool WriteJsonEventMessage(const std::string& message); 94 95 // After connect, this is called to retrieve camera dimensions 96 // and properties needed to initialize the v4l2 device and allocate 97 // buffers necessary for streaming. 98 Result<bool> ReadSettingsFromJson(const Json::Value& json); 99 100 // Established the vsock connection 101 bool Connect(); 102 103 // Called once every frame to write a frame buffer to the v4l2 104 // output device. 105 void WriteFrame(const std::vector<char>& frame, std::vector<char>& rgb_frame); 106 107 protected: 108 VsockFrameSource() = default; 109 }; 110 111 } // End namespace cuttlefish