1 #include "FakeVideoTrackSource.h"
2 
3 #include "api/video/i420_buffer.h"
4 #include "media/base/video_broadcaster.h"
5 #include "pc/video_track_source.h"
6 
7 #include "libyuv.h"
8 
9 #include <thread>
10 
11 namespace tgcalls {
12 
13 int WIDTH = 1280;
14 int HEIGHT = 720;
15 
16 class ChessFrameSource : public FrameSource {
17 public:
ChessFrameSource()18   ChessFrameSource() {
19     int N = 100;
20     frames_.reserve(N);
21     for (int i = 0; i < N; i++) {
22       frames_.push_back(genFrame(i, N));
23     }
24   }
info() const25   Info info() const override{
26     return Info{WIDTH, HEIGHT};
27   }
28 //  webrtc::VideoFrame next_frame() override {
29 //    i = (i + 1) % frames_.size();
30 //    return frames_[i].frame;
31 //  }
next_frame_rgb0(char * buf,double * pts)32   void next_frame_rgb0(char *buf, double *pts) override {
33     *pts = 0;
34     i = (i + 1) % frames_.size();
35     size_t size = WIDTH * HEIGHT * 4;
36     memcpy(buf, frames_[i].rbga.get(), size);
37   }
38 
39 private:
40   struct Frame {
41     webrtc::VideoFrame frame;
42     std::unique_ptr<std::uint8_t[]> rbga;
43   };
44   std::vector<Frame> frames_;
45   size_t i = 0;
genFrame(int i,int n)46   Frame genFrame(int i, int n) {
47     int width = WIDTH;
48     int height = HEIGHT;
49     auto bytes_ptr = std::make_unique<std::uint8_t[]>(width * height * 4);
50     auto bytes = bytes_ptr.get();
51     auto set_rgb = [&](int x, int y, std::uint8_t r, std::uint8_t g, std::uint8_t b) {
52       auto dest = bytes + (x * width + y) * 4;
53       dest[0] = r;
54       dest[1] = g;
55       dest[2] = b;
56       dest[3] = 0;
57     };
58     auto angle = (double)i / n * M_PI;
59     auto co = cos(angle);
60     auto si = sin(angle);
61 
62     for (int i = 0; i < height; i++) {
63       for (int j = 0; j < width; j++) {
64         double sx = (i - height / 2) * 20.0 / HEIGHT;
65         double sy = (j  - width / 2) * 20.0 / HEIGHT;
66 
67         int x, y;
68         if (sx * sx + sy * sy < 10) {
69           x = int(floor(sx * co - sy * si));
70           y = int(floor(sx * si + sy * co));
71         } else {
72           x = int(floor(sx));
73           y = int(floor(sy));
74         }
75         std::uint8_t color = ((y & 1) ^ (x & 1)) * 255;
76         set_rgb(i, j, color, color, color);
77       }
78     }
79 
80     rtc::scoped_refptr<webrtc::I420Buffer> buffer = webrtc::I420Buffer::Create(width, height);
81 
82     libyuv::RGBAToI420(bytes, width * 4, buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataU(),
83                        buffer->StrideU(), buffer->MutableDataV(), buffer->StrideV(), width, height);
84 
85     return Frame{webrtc::VideoFrame::Builder().set_video_frame_buffer(buffer).build(), std::move(bytes_ptr)};
86   }
87 
88 };
89 
next_frame()90 webrtc::VideoFrame FrameSource::next_frame() {
91   auto info = this->info();
92   auto height = info.height;
93   auto width = info.width;
94   auto bytes_ptr = std::make_unique<std::uint8_t[]>(width * height * 4);
95   double pts;
96   next_frame_rgb0(reinterpret_cast<char *>(bytes_ptr.get()), &pts);
97   rtc::scoped_refptr<webrtc::I420Buffer> buffer = webrtc::I420Buffer::Create(width, height);
98   libyuv::ABGRToI420(bytes_ptr.get(), width * 4, buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataU(),
99                      buffer->StrideU(), buffer->MutableDataV(), buffer->StrideV(), width, height);
100   return webrtc::VideoFrame::Builder().set_timestamp_us(static_cast<int64_t>(pts * 1000000)).set_video_frame_buffer(buffer).build();
101 }
102 
103 class FakeVideoSource : public rtc::VideoSourceInterface<webrtc::VideoFrame> {
104  public:
FakeVideoSource(std::unique_ptr<FrameSource> source)105   FakeVideoSource(std::unique_ptr<FrameSource> source) {
106     data_ = std::make_shared<Data>();
107     std::thread([data = data_, source = std::move(source)] {
108       std::uint32_t step = 0;
109       while (!data->flag_) {
110         step++;
111         std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 30));
112         auto frame = source->next_frame();
113         frame.set_id(static_cast<std::uint16_t>(step));
114         frame.set_timestamp_us(rtc::TimeMicros());
115         data->broadcaster_.OnFrame(frame);
116       }
117     }).detach();
118   }
~FakeVideoSource()119   ~FakeVideoSource() {
120     data_->flag_ = true;
121   }
122   using VideoFrameT = webrtc::VideoFrame;
AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrameT> * sink,const rtc::VideoSinkWants & wants)123   void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrameT> *sink, const rtc::VideoSinkWants &wants) override {
124     RTC_LOG(WARNING) << "ADD";
125     data_->broadcaster_.AddOrUpdateSink(sink, wants);
126   }
127   // RemoveSink must guarantee that at the time the method returns,
128   // there is no current and no future calls to VideoSinkInterface::OnFrame.
RemoveSink(rtc::VideoSinkInterface<VideoFrameT> * sink)129   void RemoveSink(rtc::VideoSinkInterface<VideoFrameT> *sink) {
130     RTC_LOG(WARNING) << "REMOVE";
131     data_->broadcaster_.RemoveSink(sink);
132   }
133 
134  private:
135   struct Data {
136     std::atomic<bool> flag_;
137     rtc::VideoBroadcaster broadcaster_;
138   };
139   std::shared_ptr<Data> data_;
140 };
141 
142 class FakeVideoTrackSourceImpl : public webrtc::VideoTrackSource {
143  public:
Create(std::unique_ptr<FrameSource> source)144   static rtc::scoped_refptr<FakeVideoTrackSourceImpl> Create(std::unique_ptr<FrameSource> source) {
145     return rtc::scoped_refptr<FakeVideoTrackSourceImpl>(new rtc::RefCountedObject<FakeVideoTrackSourceImpl>(std::move(source)));
146   }
147 
FakeVideoTrackSourceImpl(std::unique_ptr<FrameSource> source)148   explicit FakeVideoTrackSourceImpl(std::unique_ptr<FrameSource> source) : VideoTrackSource(false), source_(std::move(source)) {
149   }
150 
151  protected:
152   FakeVideoSource source_;
source()153   rtc::VideoSourceInterface<webrtc::VideoFrame> *source() override {
154     return &source_;
155   }
156 };
157 
create(std::unique_ptr<FrameSource> frame_source)158 std::function<webrtc::VideoTrackSourceInterface*()> FakeVideoTrackSource::create(std::unique_ptr<FrameSource> frame_source) {
159   auto source = FakeVideoTrackSourceImpl::Create(std::move(frame_source));
160   return [source] {
161     return source.get();
162   };
163 }
chess()164 std::unique_ptr<FrameSource> FrameSource::chess(){
165   return std::make_unique<ChessFrameSource>();
166 }
167 
video_frame_to_rgb0(const webrtc::VideoFrame & src,char * dest)168 void FrameSource::video_frame_to_rgb0(const webrtc::VideoFrame & src, char *dest){
169   auto buffer = src.video_frame_buffer()->GetI420();
170   libyuv::I420ToABGR(buffer->DataY(), buffer->StrideY(), buffer->DataU(),
171                      buffer->StrideU(), buffer->DataV(), buffer->StrideV( ), reinterpret_cast<uint8_t *>(dest), src.width() * 4,  src.width(), src.height());
172 }
173 }
174