Advertisement
Guest User

Untitled

a guest
Jun 1st, 2017
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.61 KB | None | 0 0
  1. #include "audiorenderer.h"
  2. #include "videorenderer.h"
  3. #include "audiocapturemodule.h"
  4. #include "yuvframecapture.h"
  5. #include "conductor.h"
  6.  
  7. #include "webrtc/api/test/fakeconstraints.h"
  8. #include "webrtc/video_encoder.h"
  9. #include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
  10. #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
  11. #include "webrtc/modules/video_capture/video_capture_factory.h"
  12. #include "webrtc/media/engine/webrtcvideocapturerfactory.h"
  13.  
  14. // for servers
  15. #include "webrtc/p2p/base/relayserver.h"
  16. #include "webrtc/p2p/base/stunserver.h"
  17. #include "webrtc/p2p/base/basicpacketsocketfactory.h"
  18. #include "webrtc/p2p/base/turnserver.h"
  19. #include "webrtc/base/asyncudpsocket.h"
  20. #include "webrtc/base/optionsfile.h"
  21. #include "webrtc/base/stringencode.h"
  22. #include "webrtc/base/thread.h"
  23.  
  24. namespace nr_webrtc
  25. {
  26. const char kAudioLabel[] = "audio_label";
  27. const char kVideoLabel[] = "video_label";
  28. const char kStreamLabel[] = "stream_label";
  29. const char kSoftware[] = "libjingle TurnServer";
  30.  
  31. class TurnFileAuth : public cricket::TurnAuthInterface
  32. {
  33. public:
  34. explicit TurnFileAuth(const std::string& path) : file_(path)
  35. {
  36. }
  37.  
  38. bool Load()
  39. {
  40. return file_.Load();
  41. }
  42.  
  43. virtual bool GetKey(const std::string& username, const std::string& realm, std::string* key)
  44. {
  45. // File is stored as lines of <username>=<HA1>.
  46. // Generate HA1 via "echo -n "<username>:<realm>:<password>" | md5sum"
  47. std::string hex;
  48. bool ret = file_.GetStringValue(username, &hex);
  49. if (ret)
  50. {
  51. char buf[32];
  52. size_t len = rtc::hex_decode(buf, sizeof(buf), hex);
  53. *key = std::string(buf, len);
  54. }
  55. return ret;
  56. }
  57. private:
  58. rtc::OptionsFile file_;
  59. };
  60.  
  61. Conductor::Conductor()
  62. {
  63. this->OnErrorHook = nullptr;
  64. this->OnSuccessHook = nullptr;
  65. this->OnFailureHook = nullptr;
  66. this->OnIceCandidateHook = nullptr;
  67. this->OnDataMessageHook = nullptr;
  68. this->OnDataBinaryMessageHook = nullptr;
  69.  
  70. this->width = 640;
  71. this->height = 360;
  72. this->caputureFps = 5;
  73.  
  74. this->turn_server = nullptr;
  75. this->stun_server = nullptr;
  76. this->data_channel = nullptr;
  77.  
  78. this->video_capture = nullptr;
  79. this->audio_capture = nullptr;
  80.  
  81. this->worker_thread = nullptr;
  82. this->signaling_thread = nullptr;
  83. }
  84.  
  85. Conductor::~Conductor()
  86. {
  87. this->DeInitialize();
  88. ASSERT(peer_connection == nullptr);
  89.  
  90. this->signaling_thread = nullptr;
  91. if (this->worker_thread)
  92. {
  93. this->worker_thread->Quit();
  94. delete this->worker_thread;
  95. }
  96.  
  97. if (turn_server)
  98. turn_server->disconnect_all();
  99.  
  100. if (stun_server)
  101. stun_server->disconnect_all();
  102.  
  103. if (turn_server || stun_server)
  104. rtc::Thread::Current()->Quit();
  105. }
  106.  
  107. bool Conductor::Initialize(bool audio_stream, bool video_stream) {
  108. ASSERT(pc_factory == nullptr);
  109. ASSERT(peer_connection == nullptr);
  110.  
  111. if (audio_stream)
  112. this->audio_capture = new AudioCaptureModule();
  113.  
  114. this->signaling_thread = new rtc::Thread();
  115. bool wrap = this->signaling_thread->WrapCurrent();
  116. ASSERT(wrap);
  117.  
  118. /* this->worker_thread = new rtc::Thread();
  119. bool start = this->worker_thread->Start();
  120. ASSERT(start);*/
  121.  
  122. this->pc_factory = webrtc::CreatePeerConnectionFactory(
  123. this->signaling_thread,
  124. this->signaling_thread,
  125. this->audio_capture,
  126. nullptr,
  127. nullptr);
  128.  
  129. if (!this->pc_factory)
  130. return false;
  131.  
  132. webrtc::PeerConnectionFactoryInterface::Options opt;
  133. {
  134. //opt.disable_encryption = true;
  135. //opt.disable_network_monitor = true;
  136. //opt.disable_sctp_data_channels = true;
  137. this->pc_factory->SetOptions(opt);
  138. }
  139.  
  140. if (!this->CreatePeerConnection(true))
  141. return false;
  142.  
  143. return this->AddStreams(audio_stream, video_stream) && this->peer_connection != nullptr;
  144. }
  145.  
  146. void Conductor::DeInitialize()
  147. {
  148. if (this->data_channel)
  149. {
  150. this->data_channel->UnregisterObserver();
  151. this->data_channel = nullptr;
  152. }
  153.  
  154. this->audio_capture = nullptr;
  155. this->video_capture = nullptr;
  156. this->local_video.reset(nullptr);
  157.  
  158. if (this->peer_connection.get())
  159. {
  160. for (auto it = this->active_streams.begin(); it != this->active_streams.end(); ++it) {
  161. this->peer_connection->RemoveStream(it->second);
  162. }
  163.  
  164. this->active_streams.clear();
  165. this->peer_connection->Close();
  166. this->peer_connection = nullptr;
  167. }
  168.  
  169. this->serverConfigs.clear();
  170. this->pc_factory = nullptr;
  171. }
  172.  
  173. bool Conductor::CreatePeerConnection(bool dtls)
  174. {
  175. ASSERT(pc_factory != nullptr);
  176. ASSERT(peer_connection == nullptr);
  177.  
  178. webrtc::PeerConnectionInterface::RTCConfiguration config;
  179. config.tcp_candidate_policy = webrtc::PeerConnectionInterface::kTcpCandidatePolicyDisabled;
  180. config.disable_ipv6 = true;
  181. config.enable_dtls_srtp = rtc::Optional<bool>(dtls);
  182. config.rtcp_mux_policy = webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire;
  183.  
  184. for each (auto server in this->serverConfigs) {
  185. config.servers.push_back(server);
  186. }
  187.  
  188. webrtc::FakeConstraints constraints;
  189. constraints.SetAllowDtlsSctpDataChannels();
  190. constraints.SetMandatoryReceiveVideo(false);
  191. constraints.SetMandatoryReceiveAudio(false);
  192. constraints.SetMandatoryIceRestart(true);
  193. constraints.SetMandatoryUseRtpMux(true);
  194. constraints.AddMandatory(webrtc::MediaConstraintsInterface::kVoiceActivityDetection, "false");
  195. constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableIPv6, "false");
  196.  
  197. this->peer_connection = this->pc_factory->CreatePeerConnection(config, &constraints, NULL, NULL, this);
  198. return this->peer_connection != nullptr;
  199. }
  200.  
  201. bool Conductor::AddStreams(bool audio_stream, bool video_stream)
  202. {
  203. if (this->active_streams.find(kStreamLabel) != this->active_streams.end())
  204. return false; // Already added.
  205.  
  206. auto stream = this->pc_factory->CreateLocalMediaStream(kStreamLabel);
  207.  
  208. if (audio_stream) {
  209. auto a = this->pc_factory->CreateAudioSource(NULL);
  210. auto audio_track = this->pc_factory->CreateAudioTrack(kAudioLabel, a);
  211. stream->AddTrack(audio_track);
  212. }
  213.  
  214. if (video_stream) {
  215. this->video_capture = new nr_webrtc::YuvFrameCapture(*this);
  216. auto v = this->pc_factory->CreateVideoSource(this->video_capture);
  217. auto video_track = pc_factory->CreateVideoTrack(kVideoLabel, v);
  218. stream->AddTrack(video_track);
  219. this->local_video.reset(new VideoRenderer(*this, false, video_track));
  220. }
  221.  
  222. if (!this->peer_connection->AddStream(stream))
  223. {
  224. stream = nullptr;
  225. return false;
  226. }
  227.  
  228. typedef std::pair<std::string, rtc::scoped_refptr<webrtc::MediaStreamInterface>> MediaStreamPair;
  229. this->active_streams.insert(MediaStreamPair(stream->label(), stream));
  230.  
  231. return true;
  232. }
  233.  
  234. bool Conductor::ProcessMessages(int delay) {
  235. return rtc::Thread::Current()->ProcessMessages(delay);
  236. }
  237.  
  238. uint8_t * Conductor::VideoCapturerI420Buffer() {
  239. if (this->video_capture)
  240. return (uint8_t*)this->video_capture->video_buffer->DataY();
  241.  
  242. return nullptr;
  243. }
  244.  
  245. void Conductor::PushVideoFrame(uint8_t * rgbBuffer, int bits) {
  246. auto yuv = this->VideoCapturerI420Buffer();
  247. if (yuv)
  248. {
  249. Conductor::RGBToYUVI420(this->width, this->height, bits, rgbBuffer, yuv);
  250. this->video_capture->PushFrame();
  251. }
  252. }
  253.  
  254. void Conductor::PushAudioFrame(const void* audio_data, int bits_per_sample, int sample_rate, int number_of_channels, int number_of_frames) {
  255. if (this->audio_capture)
  256. this->audio_capture->PushFrame(audio_data, bits_per_sample, sample_rate, number_of_channels, number_of_frames);
  257. }
  258.  
  259. bool Conductor::IsRecordingAudio() {
  260. return this->audio_capture && this->audio_capture->Recording();
  261. }
  262.  
  263. bool Conductor::IsRecordingVideo() {
  264. return this->video_capture && this->video_capture->IsRunning();
  265. }
  266.  
  267. void Conductor::AddServerConfig(std::string uri, std::string username, std::string password)
  268. {
  269. webrtc::PeerConnectionInterface::IceServer server;
  270. server.uri = uri;
  271. server.username = username;
  272. server.password = password;
  273.  
  274. serverConfigs.push_back(server);
  275. }
  276.  
  277. void Conductor::CreateOffer()
  278. {
  279. peer_connection->CreateOffer(this, nullptr);
  280. }
  281.  
  282. void Conductor::OnOfferReply(std::string type, std::string sdp)
  283. {
  284. webrtc::SdpParseError error;
  285. webrtc::SessionDescriptionInterface* session_description(webrtc::CreateSessionDescription(type, sdp, &error));
  286. if (!session_description)
  287. {
  288. LOG(WARNING) << "Can't parse received session description message. " << "SdpParseError was: " << error.description;
  289. return;
  290. }
  291. peer_connection->SetRemoteDescription(this, session_description);
  292. }
  293.  
  294. void Conductor::OnOfferRequest(std::string sdp)
  295. {
  296. webrtc::SdpParseError error;
  297. webrtc::SessionDescriptionInterface* session_description(webrtc::CreateSessionDescription("offer", sdp, &error));
  298. if (!session_description)
  299. {
  300. LOG(WARNING) << "Can't parse received session description message. " << "SdpParseError was: " << error.description;
  301. return;
  302. }
  303. peer_connection->SetRemoteDescription(this, session_description);
  304.  
  305. webrtc::PeerConnectionInterface::RTCOfferAnswerOptions o;
  306. {
  307. o.voice_activity_detection = false;
  308. o.offer_to_receive_audio = false;
  309. o.offer_to_receive_video = webrtc::PeerConnectionInterface::RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
  310. }
  311. peer_connection->CreateAnswer(this, o);
  312. }
  313.  
  314. bool Conductor::AddIceCandidate(std::string sdp_mid, int sdp_mlineindex, std::string sdp)
  315. {
  316. webrtc::SdpParseError error;
  317. webrtc::IceCandidateInterface * candidate = webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error);
  318. if (!candidate)
  319. {
  320. LOG(WARNING) << "Can't parse received candidate message. " << "SdpParseError was: " << error.description;
  321. return false;
  322. }
  323.  
  324. if (!peer_connection)
  325. return false;
  326.  
  327. if (!peer_connection->AddIceCandidate(candidate))
  328. {
  329. LOG(WARNING) << "Failed to apply the received candidate";
  330. return false;
  331. }
  332.  
  333. return true;
  334. }
  335.  
  336. std::vector<std::string> Conductor::GetVideoDevices()
  337. {
  338. std::vector<std::string> device_names;
  339. {
  340. std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(webrtc::VideoCaptureFactory::CreateDeviceInfo());
  341. if (info)
  342. {
  343. int num_devices = info->NumberOfDevices();
  344. for (int i = 0; i < num_devices; ++i)
  345. {
  346. const uint32_t kSize = 256;
  347. char name[kSize] = { 0 };
  348. char id[kSize] = { 0 };
  349. if (info->GetDeviceName(i, name, kSize, id, kSize) != -1)
  350. {
  351. device_names.push_back(name);
  352. }
  353. }
  354. }
  355. }
  356. return device_names;
  357. }
  358.  
  359. // Called when a remote stream is added
  360. void Conductor::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
  361. {
  362. LOG(INFO) << __FUNCTION__ << " " << stream->label();
  363.  
  364. if (this->OnRenderVideoHook)
  365. {
  366. webrtc::VideoTrackVector vtracks = stream->GetVideoTracks();
  367. if (!vtracks.empty())
  368. {
  369. webrtc::VideoTrackInterface* track = vtracks[0];
  370. remote_video.reset(new nr_webrtc::VideoRenderer(*this, true, track));
  371. }
  372. }
  373.  
  374. if (this->OnRenderAudioHook)
  375. {
  376. webrtc::AudioTrackVector atracks = stream->GetAudioTracks();
  377. if (!atracks.empty())
  378. {
  379. webrtc::AudioTrackInterface* track = atracks[0];
  380. remote_audio.reset(new nr_webrtc::AudioRenderer(*this, true, track));
  381. }
  382. }
  383. }
  384.  
  385. void Conductor::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
  386. {
  387. LOG(INFO) << __FUNCTION__ << " " << stream->label();
  388. remote_video.reset(nullptr);
  389. remote_audio.reset(nullptr);
  390.  
  391. // lost ownership, do not delete
  392. /*capturer = nullptr;
  393. capturer_internal = nullptr;*/
  394. }
  395.  
  396. void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate)
  397. {
  398. LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
  399.  
  400. std::string sdp;
  401. if (!candidate->ToString(&sdp))
  402. {
  403. LOG(LS_ERROR) << "Failed to serialize candidate";
  404. return;
  405. }
  406.  
  407. if (this->OnIceCandidateHook != nullptr)
  408. this->OnIceCandidateHook(candidate->sdp_mid().c_str(), candidate->sdp_mline_index(), sdp.c_str());
  409. }
  410.  
  411. void Conductor::OnSuccess(webrtc::SessionDescriptionInterface* desc)
  412. {
  413. peer_connection->SetLocalDescription(this, desc);
  414.  
  415. std::string sdp;
  416. desc->ToString(&sdp);
  417.  
  418. if (this->OnSuccessHook != nullptr)
  419. this->OnSuccessHook(desc->type().c_str(), sdp.c_str());
  420. }
  421.  
  422. void Conductor::OnFailure(const std::string& error)
  423. {
  424. LOG(LERROR) << error;
  425.  
  426. if (this->OnFailureHook != nullptr)
  427. this->OnFailureHook(error.c_str());
  428. }
  429.  
  430. void Conductor::OnError()
  431. {
  432. if (this->OnErrorHook != nullptr)
  433. this->OnErrorHook();
  434. }
  435.  
  436. void Conductor::CreateDataChannel(const std::string & label)
  437. {
  438. if (!this->peer_connection)
  439. return;
  440.  
  441. webrtc::DataChannelInit dc_options;
  442. //dc_options.id = 1;
  443. dc_options.maxRetransmits = 1;
  444. dc_options.negotiated = false;
  445. dc_options.ordered = false;
  446.  
  447. this->data_channel = this->peer_connection->CreateDataChannel(label, &dc_options);
  448. this->data_channel->RegisterObserver(this);
  449. }
  450.  
  451. void Conductor::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> channel)
  452. {
  453. LOG(INFO) << __FUNCTION__ << " " << channel->label();
  454.  
  455. this->data_channel = channel.get();
  456. this->data_channel->RegisterObserver(this);
  457. }
  458.  
  459. bool Conductor::DataChannelSendText(const std::string & text)
  460. {
  461. return this->data_channel && this->data_channel->Send(webrtc::DataBuffer(text));
  462. }
  463.  
  464. bool Conductor::DataChannelSendData(const webrtc::DataBuffer & data)
  465. {
  466. return this->data_channel && this->data_channel->Send(data);
  467. }
  468.  
  469. bool Conductor::IsDataChannelConnected() {
  470. return this->data_channel != nullptr;
  471. }
  472.  
  473. // A data buffer was successfully received.
  474. void Conductor::OnMessage(const webrtc::DataBuffer& buffer)
  475. {
  476. LOG(INFO) << __FUNCTION__;
  477.  
  478. if (buffer.binary)
  479. {
  480. if (this->OnDataBinaryMessageHook != nullptr)
  481. {
  482. auto * data = buffer.data.data();
  483. this->OnDataBinaryMessageHook(data, buffer.size());
  484. }
  485. }
  486. else
  487. {
  488. if (this->OnDataMessageHook != nullptr)
  489. {
  490. std::string msg(buffer.data.data<char>(), buffer.size());
  491. this->OnDataMessageHook(msg.c_str());
  492. }
  493. }
  494. }
  495.  
  496. bool Conductor::RunStunServer(const std::string & bindIp)
  497. {
  498. rtc::SocketAddress server_addr;
  499. if (!server_addr.FromString(bindIp))
  500. {
  501. LOG(LERROR) << "Unable to parse IP address: " << bindIp;
  502. return false;
  503. }
  504.  
  505. rtc::Thread * main = rtc::Thread::Current();
  506.  
  507. rtc::AsyncUDPSocket* server_socket = rtc::AsyncUDPSocket::Create(main->socketserver(), server_addr);
  508. if (!server_socket)
  509. {
  510. LOG(LERROR) << "Failed to create a UDP socket" << std::endl;
  511. return false;
  512. }
  513.  
  514. stun_server.reset(new cricket::StunServer(server_socket));
  515.  
  516. LOG(INFO) << "Listening at " << server_addr.ToString() << std::endl;
  517.  
  518. return true;
  519. }
  520.  
  521. bool Conductor::RunTurnServer(const std::string & bindIp, const std::string & ip,
  522. const std::string & realm, const std::string & authFile)
  523. {
  524. rtc::SocketAddress int_addr;
  525. if (!int_addr.FromString(bindIp))
  526. {
  527. LOG(LERROR) << "Unable to parse IP address: " << bindIp << std::endl;
  528. return false;
  529. }
  530.  
  531. rtc::IPAddress ext_addr;
  532. if (!IPFromString(ip, &ext_addr))
  533. {
  534. LOG(LERROR) << "Unable to parse IP address: " << ip << std::endl;
  535. return false;
  536. }
  537.  
  538. rtc::Thread* main = rtc::Thread::Current();
  539. rtc::AsyncUDPSocket * int_socket = rtc::AsyncUDPSocket::Create(main->socketserver(), int_addr);
  540. if (!int_socket)
  541. {
  542. LOG(LERROR) << "Failed to create a UDP socket bound at" << int_addr.ToString() << std::endl;
  543. return false;
  544. }
  545.  
  546. TurnFileAuth * auth = new TurnFileAuth(authFile);
  547. if (!auth->Load())
  548. {
  549. LOG(LERROR) << "Failed to load auth file " << authFile << std::endl;
  550. return false;
  551. }
  552.  
  553.  
  554. auto t = new cricket::TurnServer(main);
  555. turn_server.reset(t);
  556.  
  557. t->set_realm(realm);
  558. t->set_software(kSoftware);
  559. t->set_auth_hook(auth);
  560. t->AddInternalSocket(int_socket, cricket::PROTO_UDP);
  561. t->SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(),
  562. rtc::SocketAddress(ext_addr, 0));
  563.  
  564. LOG(INFO) << "Listening internally at " << int_addr.ToString() << std::endl;
  565.  
  566. return true;
  567. }
  568.  
  569. void Conductor::RGBToYUVI420(int width, int height, int bits, uint8_t * image, uint8_t * yuv)
  570. {
  571. int pitch = bits / 8;
  572. int stride = width * pitch;
  573. int strideY = width;
  574. int strideU = width / 2;
  575. int strideV = width / 2;
  576.  
  577. uint8_t * pimageY = yuv;
  578. uint8_t * pimageU = yuv + strideY * height;
  579. uint8_t * pimageV = yuv + strideY * height + (strideU * ((height + 1) / 2));
  580.  
  581. int i = 0;
  582. for (int y = 0; y < height; y += 2)
  583. for (int x = 0; x < width; x += 2)
  584. {
  585. int xi = pitch * x;
  586. int yi = height - y - 1;
  587. int xyi = yi * stride + xi;
  588. int yxi = (yi - 1) * stride + xi;
  589.  
  590. uint8_t r00 = image[xyi + 0];
  591. uint8_t g00 = image[xyi + 1];
  592. uint8_t b00 = image[xyi + 2];
  593.  
  594. uint8_t r01 = image[xyi + 4];
  595. uint8_t g01 = image[xyi + 5];
  596. uint8_t b01 = image[xyi + 6];
  597.  
  598. uint8_t r10 = image[yxi + 0];
  599. uint8_t g10 = image[yxi + 1];
  600. uint8_t b10 = image[yxi + 2];
  601.  
  602. uint8_t r11 = image[yxi + 4];
  603. uint8_t g11 = image[yxi + 5];
  604. uint8_t b11 = image[yxi + 6];
  605.  
  606. pimageY[y * width + x] = (((66 * r00 + 129 * g00 + 25 * b00 + 128) >> 8) + 16);
  607. pimageY[y * width + x + 1] = (((66 * r01 + 129 * g01 + 25 * b01 + 128) >> 8) + 16);
  608. pimageY[(y + 1) * width + x] = (((66 * r10 + 129 * g10 + 25 * b10 + 128) >> 8) + 16);
  609. pimageY[(y + 1) * width + x + 1] = (((66 * r11 + 129 * g11 + 25 * b11 + 128) >> 8) + 16);
  610.  
  611. uint8_t u00 = (((112 * r00 - 94 * g00 - 18 * b00 + 128) >> 8) + 128);
  612. uint8_t u01 = (((112 * r01 - 94 * g01 - 18 * b01 + 128) >> 8) + 128);
  613. uint8_t u10 = (((112 * r10 - 94 * g10 - 18 * b10 + 128) >> 8) + 128);
  614. uint8_t u11 = (((112 * r11 - 94 * g11 - 18 * b11 + 128) >> 8) + 128);
  615.  
  616. uint8_t v00 = (((-38 * r00 - 74 * g00 + 112 * b00 + 128) >> 8) + 128);
  617. uint8_t v01 = (((-38 * r01 - 74 * g01 + 112 * b01 + 128) >> 8) + 128);
  618. uint8_t v10 = (((-38 * r10 - 74 * g10 + 112 * b10 + 128) >> 8) + 128);
  619. uint8_t v11 = (((-38 * r11 - 74 * g11 + 112 * b11 + 128) >> 8) + 128);
  620.  
  621. pimageU[i] = ((u00 + u01 + u10 + u11) / 4);
  622. pimageV[i++] = ((v00 + v01 + v10 + v11) / 4);
  623. }
  624. }
  625.  
  626. void Conductor::YUVI420ToRGB(int width, int height, int bits, uint8_t * image, uint8_t * yuv)
  627. {
  628. int i = 0;
  629. int pitch = bits / 8;
  630. int pixels = width * height;
  631. int stride = width * pitch;
  632.  
  633. int strideY = width;
  634. int strideU = width / 2;
  635. int strideV = width / 2;
  636.  
  637. uint8_t * imageY = yuv;
  638. uint8_t * imageU = yuv + strideY * height;
  639. uint8_t * imageV = yuv + strideY * height + (strideU * ((height + 1) / 2));
  640.  
  641. for (int yCord = 0; yCord < height; yCord++)
  642. {
  643. for (int xCord = 0; xCord < width; xCord += 2)
  644. {
  645. int c1 = imageY[yCord * strideY + xCord] - 16;
  646. int c2 = imageY[yCord * strideY + xCord + 1] - 16;
  647. int d = imageU[yCord / 2 * strideU + xCord / 2] - 128;
  648. int e = imageV[yCord / 2 * strideV + xCord / 2] - 128;
  649.  
  650. image[i++] = std::min(255, std::max(0, (298 * c1 + 409 * e + 128) >> 8));//r
  651. image[i++] = std::min(255, std::max(0, (298 * c1 - 100 * d - 208 * e + 128) >> 8));//g
  652. image[i++] = std::min(255, std::max(0, (298 * c1 + 516 * d + 128) >> 8));//b
  653.  
  654. image[i++] = std::min(255, std::max(0, (298 * c2 + 409 * e + 128) >> 8));//r
  655. image[i++] = std::min(255, std::max(0, (298 * c2 - 100 * d - 208 * e + 128) >> 8));//g
  656. image[i++] = std::min(255, std::max(0, (298 * c2 + 516 * d + 128) >> 8));//b
  657. }
  658. }
  659. }
  660. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement