| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <math.h> | 5 #include <math.h> |
| 6 #include <stdio.h> | 6 #include <stdio.h> |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <deque> | 10 #include <deque> |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 #define fourcc(a, b, c, d) \ | 42 #define fourcc(a, b, c, d) \ |
| 43 (((uint32_t)(a) << 0) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | \ | 43 (((uint32_t)(a) << 0) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | \ |
| 44 ((uint32_t)(d) << 24)) | 44 ((uint32_t)(d) << 24)) |
| 45 | 45 |
| 46 namespace { | 46 namespace { |
| 47 | 47 |
| 48 double clamp(double min, double max, double value) { | 48 double clamp(double min, double max, double value) { |
| 49 return std::max(std::min(value, max), min); | 49 return std::max(std::min(value, max), min); |
| 50 } | 50 } |
| 51 | 51 |
| 52 std::string ToUpperString(const std::string& str) { |
| 53 std::string ret; |
| 54 for (uint32_t i = 0; i < str.size(); i++) |
| 55 ret.push_back(static_cast<char>(toupper(str[i]))); |
| 56 return ret; |
| 57 } |
| 58 |
| 52 // IVF container writer. It is possible to parse H264 bitstream using | 59 // IVF container writer. It is possible to parse H264 bitstream using |
| 53 // NAL units but for VP8 we need a container to at least find encoded | 60 // NAL units but for VP8 we need a container to at least find encoded |
| 54 // pictures as well as the picture sizes. | 61 // pictures as well as the picture sizes. |
| 55 class IVFWriter { | 62 class IVFWriter { |
| 56 public: | 63 public: |
| 57 IVFWriter() {} | 64 IVFWriter() {} |
| 58 ~IVFWriter() {} | 65 ~IVFWriter() {} |
| 59 | 66 |
| 60 uint32_t GetFileHeaderSize() const { return 32; } | 67 uint32_t GetFileHeaderSize() const { return 32; } |
| 61 uint32_t GetFrameHeaderSize() const { return 12; } | 68 uint32_t GetFrameHeaderSize() const { return 12; } |
| 62 uint32_t WriteFileHeader(uint8_t* mem, int32_t width, int32_t height); | 69 uint32_t WriteFileHeader(uint8_t* mem, |
| 70 const std::string& codec, |
| 71 int32_t width, |
| 72 int32_t height); |
| 63 uint32_t WriteFrameHeader(uint8_t* mem, uint64_t pts, size_t frame_size); | 73 uint32_t WriteFrameHeader(uint8_t* mem, uint64_t pts, size_t frame_size); |
| 64 | 74 |
| 65 private: | 75 private: |
| 66 void PutLE16(uint8_t* mem, int val) const { | 76 void PutLE16(uint8_t* mem, int val) const { |
| 67 mem[0] = (val >> 0) & 0xff; | 77 mem[0] = (val >> 0) & 0xff; |
| 68 mem[1] = (val >> 8) & 0xff; | 78 mem[1] = (val >> 8) & 0xff; |
| 69 } | 79 } |
| 70 void PutLE32(uint8_t* mem, int val) const { | 80 void PutLE32(uint8_t* mem, int val) const { |
| 71 mem[0] = (val >> 0) & 0xff; | 81 mem[0] = (val >> 0) & 0xff; |
| 72 mem[1] = (val >> 8) & 0xff; | 82 mem[1] = (val >> 8) & 0xff; |
| 73 mem[2] = (val >> 16) & 0xff; | 83 mem[2] = (val >> 16) & 0xff; |
| 74 mem[3] = (val >> 24) & 0xff; | 84 mem[3] = (val >> 24) & 0xff; |
| 75 } | 85 } |
| 76 }; | 86 }; |
| 77 | 87 |
| 78 uint32_t IVFWriter::WriteFileHeader(uint8_t* mem, | 88 uint32_t IVFWriter::WriteFileHeader(uint8_t* mem, |
| 89 const std::string& codec, |
| 79 int32_t width, | 90 int32_t width, |
| 80 int32_t height) { | 91 int32_t height) { |
| 81 mem[0] = 'D'; | 92 mem[0] = 'D'; |
| 82 mem[1] = 'K'; | 93 mem[1] = 'K'; |
| 83 mem[2] = 'I'; | 94 mem[2] = 'I'; |
| 84 mem[3] = 'F'; | 95 mem[3] = 'F'; |
| 85 PutLE16(mem + 4, 0); // version | 96 PutLE16(mem + 4, 0); // version |
| 86 PutLE16(mem + 6, 32); // header size | 97 PutLE16(mem + 6, 32); // header size |
| 87 PutLE32(mem + 8, fourcc('V', 'P', '8', '0')); // fourcc | 98 PutLE32(mem + 8, fourcc(codec[0], codec[1], codec[2], '0')); // fourcc |
| 88 PutLE16(mem + 12, static_cast<uint16_t>(width)); // width | 99 PutLE16(mem + 12, static_cast<uint16_t>(width)); // width |
| 89 PutLE16(mem + 14, static_cast<uint16_t>(height)); // height | 100 PutLE16(mem + 14, static_cast<uint16_t>(height)); // height |
| 90 PutLE32(mem + 16, 1000); // rate | 101 PutLE32(mem + 16, 1000); // rate |
| 91 PutLE32(mem + 20, 1); // scale | 102 PutLE32(mem + 20, 1); // scale |
| 92 PutLE32(mem + 24, 0xffffffff); // length | 103 PutLE32(mem + 24, 0xffffffff); // length |
| 93 PutLE32(mem + 28, 0); // unused | 104 PutLE32(mem + 28, 0); // unused |
| 94 | 105 |
| 95 return 32; | 106 return 32; |
| 96 } | 107 } |
| 97 | 108 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 void StartTrackFrames(); | 160 void StartTrackFrames(); |
| 150 void StopTrackFrames(); | 161 void StopTrackFrames(); |
| 151 void OnTrackFrame(int32_t result, pp::VideoFrame frame); | 162 void OnTrackFrame(int32_t result, pp::VideoFrame frame); |
| 152 | 163 |
| 153 void StopEncode(); | 164 void StopEncode(); |
| 154 | 165 |
| 155 void LogError(int32_t error, const std::string& message); | 166 void LogError(int32_t error, const std::string& message); |
| 156 void Log(const std::string& message); | 167 void Log(const std::string& message); |
| 157 | 168 |
| 158 void PostDataMessage(const void* buffer, uint32_t size); | 169 void PostDataMessage(const void* buffer, uint32_t size); |
| 159 void PostSignalMessage(const char* name); | |
| 160 | 170 |
| 161 typedef std::map<std::string, PP_VideoProfile> VideoProfileFromStringMap; | 171 typedef std::map<std::string, PP_VideoProfile> VideoProfileFromStringMap; |
| 162 VideoProfileFromStringMap profile_from_string_; | 172 VideoProfileFromStringMap profile_from_string_; |
| 163 | 173 |
| 164 typedef std::map<PP_VideoProfile, std::string> VideoProfileToStringMap; | 174 typedef std::map<PP_VideoProfile, std::string> VideoProfileToStringMap; |
| 165 VideoProfileToStringMap profile_to_string_; | 175 VideoProfileToStringMap profile_to_string_; |
| 166 | 176 |
| 167 bool is_encoding_; | 177 bool is_encoding_; |
| 168 bool is_encode_ticking_; | 178 bool is_encode_ticking_; |
| 169 bool is_receiving_track_frames_; | 179 bool is_receiving_track_frames_; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 frame_size_ = encoder_size_; | 266 frame_size_ = encoder_size_; |
| 257 | 267 |
| 258 int32_t attrib_list[] = {PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, | 268 int32_t attrib_list[] = {PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, |
| 259 frame_format_, | 269 frame_format_, |
| 260 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, | 270 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, |
| 261 frame_size_.width(), | 271 frame_size_.width(), |
| 262 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, | 272 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, |
| 263 frame_size_.height(), | 273 frame_size_.height(), |
| 264 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE}; | 274 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE}; |
| 265 | 275 |
| 266 pp::VarDictionary dict; | |
| 267 dict.Set(pp::Var("status"), pp::Var("configuring video track")); | |
| 268 dict.Set(pp::Var("width"), pp::Var(frame_size_.width())); | |
| 269 dict.Set(pp::Var("height"), pp::Var(frame_size_.height())); | |
| 270 PostMessage(dict); | |
| 271 | |
| 272 video_track_.Configure( | 276 video_track_.Configure( |
| 273 attrib_list, | 277 attrib_list, |
| 274 callback_factory_.NewCallback(&VideoEncoderInstance::OnConfiguredTrack)); | 278 callback_factory_.NewCallback(&VideoEncoderInstance::OnConfiguredTrack)); |
| 275 } | 279 } |
| 276 | 280 |
| 277 void VideoEncoderInstance::OnConfiguredTrack(int32_t result) { | 281 void VideoEncoderInstance::OnConfiguredTrack(int32_t result) { |
| 278 if (result != PP_OK) { | 282 if (result != PP_OK) { |
| 279 LogError(result, "Cannot configure track"); | 283 LogError(result, "Cannot configure track"); |
| 280 return; | 284 return; |
| 281 } | 285 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 300 dict.Set(pp::Var("name"), pp::Var("supportedProfiles")); | 304 dict.Set(pp::Var("name"), pp::Var("supportedProfiles")); |
| 301 pp::VarArray js_profiles; | 305 pp::VarArray js_profiles; |
| 302 dict.Set(pp::Var("profiles"), js_profiles); | 306 dict.Set(pp::Var("profiles"), js_profiles); |
| 303 | 307 |
| 304 if (result < 0) { | 308 if (result < 0) { |
| 305 LogError(result, "Cannot get supported profiles"); | 309 LogError(result, "Cannot get supported profiles"); |
| 306 PostMessage(dict); | 310 PostMessage(dict); |
| 307 } | 311 } |
| 308 | 312 |
| 309 int32_t idx = 0; | 313 int32_t idx = 0; |
| 310 for (const PP_VideoProfileDescription& profile : profiles) | 314 for (uint32_t i = 0; i < profiles.size(); i++) { |
| 315 const PP_VideoProfileDescription& profile = profiles[i]; |
| 311 js_profiles.Set(idx++, pp::Var(VideoProfileToString(profile.profile))); | 316 js_profiles.Set(idx++, pp::Var(VideoProfileToString(profile.profile))); |
| 317 } |
| 312 PostMessage(dict); | 318 PostMessage(dict); |
| 313 } | 319 } |
| 314 | 320 |
| 315 void VideoEncoderInstance::StartEncoder() { | 321 void VideoEncoderInstance::StartEncoder() { |
| 316 video_encoder_ = pp::VideoEncoder(this); | 322 video_encoder_ = pp::VideoEncoder(this); |
| 317 frames_timestamps_.clear(); | 323 frames_timestamps_.clear(); |
| 318 | 324 |
| 319 int32_t error = video_encoder_.Initialize( | 325 int32_t error = video_encoder_.Initialize( |
| 320 frame_format_, frame_size_, video_profile_, 2000000, | 326 frame_format_, frame_size_, video_profile_, 2000000, |
| 321 PP_HARDWAREACCELERATION_WITHFALLBACK, | 327 PP_HARDWAREACCELERATION_WITHFALLBACK, |
| 322 callback_factory_.NewCallback( | 328 callback_factory_.NewCallback( |
| 323 &VideoEncoderInstance::OnInitializedEncoder)); | 329 &VideoEncoderInstance::OnInitializedEncoder)); |
| 324 if (error != PP_OK_COMPLETIONPENDING) { | 330 if (error != PP_OK_COMPLETIONPENDING) { |
| 325 LogError(error, "Cannot initialize encoder"); | 331 LogError(error, "Cannot initialize encoder"); |
| 326 return; | 332 return; |
| 327 } | 333 } |
| 328 } | 334 } |
| 329 | 335 |
| 330 void VideoEncoderInstance::OnInitializedEncoder(int32_t result) { | 336 void VideoEncoderInstance::OnInitializedEncoder(int32_t result) { |
| 331 if (result != PP_OK) { | 337 if (result != PP_OK) { |
| 332 LogError(result, "Encoder initialization failed"); | 338 LogError(result, "Encoder initialization failed"); |
| 333 return; | 339 return; |
| 334 } | 340 } |
| 335 | 341 |
| 336 is_encoding_ = true; | 342 is_encoding_ = true; |
| 337 PostSignalMessage("started"); | 343 Log("started"); |
| 338 | 344 |
| 339 if (video_encoder_.GetFrameCodedSize(&encoder_size_) != PP_OK) { | 345 if (video_encoder_.GetFrameCodedSize(&encoder_size_) != PP_OK) { |
| 340 LogError(result, "Cannot get encoder coded frame size"); | 346 LogError(result, "Cannot get encoder coded frame size"); |
| 341 return; | 347 return; |
| 342 } | 348 } |
| 343 | 349 |
| 344 video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput( | 350 video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput( |
| 345 &VideoEncoderInstance::OnGetBitstreamBuffer)); | 351 &VideoEncoderInstance::OnGetBitstreamBuffer)); |
| 346 | 352 |
| 347 if (encoder_size_ != frame_size_) | 353 if (encoder_size_ != frame_size_) |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 return; | 531 return; |
| 526 } | 532 } |
| 527 pp::Resource resource_track = var_track.AsResource(); | 533 pp::Resource resource_track = var_track.AsResource(); |
| 528 video_track_ = pp::MediaStreamVideoTrack(resource_track); | 534 video_track_ = pp::MediaStreamVideoTrack(resource_track); |
| 529 video_encoder_ = pp::VideoEncoder(); | 535 video_encoder_ = pp::VideoEncoder(); |
| 530 video_profile_ = VideoProfileFromString( | 536 video_profile_ = VideoProfileFromString( |
| 531 dict_message.Get("profile").AsString()); | 537 dict_message.Get("profile").AsString()); |
| 532 ConfigureTrack(); | 538 ConfigureTrack(); |
| 533 } else if (command == "stop") { | 539 } else if (command == "stop") { |
| 534 StopEncode(); | 540 StopEncode(); |
| 535 PostSignalMessage("stopped"); | 541 Log("stopped"); |
| 536 } else { | 542 } else { |
| 537 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!")); | 543 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!")); |
| 538 } | 544 } |
| 539 } | 545 } |
| 540 | 546 |
| 541 void VideoEncoderInstance::PostDataMessage(const void* buffer, uint32_t size) { | 547 void VideoEncoderInstance::PostDataMessage(const void* buffer, uint32_t size) { |
| 542 pp::VarDictionary dictionary; | 548 pp::VarDictionary dictionary; |
| 543 | 549 |
| 544 dictionary.Set(pp::Var("name"), pp::Var("data")); | 550 dictionary.Set(pp::Var("name"), pp::Var("data")); |
| 545 | 551 |
| 546 pp::VarArrayBuffer array_buffer; | 552 pp::VarArrayBuffer array_buffer; |
| 547 uint8_t* data_ptr; | 553 uint8_t* data_ptr; |
| 548 uint32_t data_offset = 0; | 554 uint32_t data_offset = 0; |
| 549 if (video_profile_ == PP_VIDEOPROFILE_VP8_ANY || | 555 if (video_profile_ == PP_VIDEOPROFILE_VP8_ANY || |
| 550 video_profile_ == PP_VIDEOPROFILE_VP9_ANY) { | 556 video_profile_ == PP_VIDEOPROFILE_VP9_ANY) { |
| 551 uint32_t frame_offset = 0; | 557 uint32_t frame_offset = 0; |
| 552 if (encoded_frames_ == 1) { | 558 if (encoded_frames_ == 1) { |
| 553 array_buffer = pp::VarArrayBuffer( | 559 array_buffer = pp::VarArrayBuffer( |
| 554 size + ivf_writer_.GetFileHeaderSize() + | 560 size + ivf_writer_.GetFileHeaderSize() + |
| 555 ivf_writer_.GetFrameHeaderSize()); | 561 ivf_writer_.GetFrameHeaderSize()); |
| 556 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); | 562 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); |
| 557 frame_offset = ivf_writer_.WriteFileHeader( | 563 frame_offset = ivf_writer_.WriteFileHeader( |
| 558 data_ptr, frame_size_.width(), frame_size_.height()); | 564 data_ptr, ToUpperString(VideoProfileToString(video_profile_)), |
| 565 frame_size_.width(), frame_size_.height()); |
| 559 } else { | 566 } else { |
| 560 array_buffer = pp::VarArrayBuffer( | 567 array_buffer = pp::VarArrayBuffer( |
| 561 size + ivf_writer_.GetFrameHeaderSize()); | 568 size + ivf_writer_.GetFrameHeaderSize()); |
| 562 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); | 569 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); |
| 563 } | 570 } |
| 564 uint64_t timestamp = frames_timestamps_.front(); | 571 uint64_t timestamp = frames_timestamps_.front(); |
| 565 frames_timestamps_.pop_front(); | 572 frames_timestamps_.pop_front(); |
| 566 data_offset = | 573 data_offset = |
| 567 frame_offset + | 574 frame_offset + |
| 568 ivf_writer_.WriteFrameHeader(data_ptr + frame_offset, timestamp, size); | 575 ivf_writer_.WriteFrameHeader(data_ptr + frame_offset, timestamp, size); |
| 569 } else { | 576 } else { |
| 570 array_buffer = pp::VarArrayBuffer(size); | 577 array_buffer = pp::VarArrayBuffer(size); |
| 571 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); | 578 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); |
| 572 } | 579 } |
| 573 | 580 |
| 574 memcpy(data_ptr + data_offset, buffer, size); | 581 memcpy(data_ptr + data_offset, buffer, size); |
| 575 array_buffer.Unmap(); | 582 array_buffer.Unmap(); |
| 576 dictionary.Set(pp::Var("data"), array_buffer); | 583 dictionary.Set(pp::Var("data"), array_buffer); |
| 577 | 584 |
| 578 PostMessage(dictionary); | 585 PostMessage(dictionary); |
| 579 } | 586 } |
| 580 | 587 |
| 581 void VideoEncoderInstance::PostSignalMessage(const char* name) { | |
| 582 pp::VarDictionary dictionary; | |
| 583 dictionary.Set(pp::Var("name"), pp::Var(name)); | |
| 584 | |
| 585 PostMessage(dictionary); | |
| 586 } | |
| 587 | |
| 588 void VideoEncoderInstance::LogError(int32_t error, const std::string& message) { | 588 void VideoEncoderInstance::LogError(int32_t error, const std::string& message) { |
| 589 std::string msg("Error: "); | 589 std::string msg("Error: "); |
| 590 msg.append(pp::Var(error).DebugString()); | 590 msg.append(pp::Var(error).DebugString()); |
| 591 msg.append(" : "); | 591 msg.append(" : "); |
| 592 msg.append(message); | 592 msg.append(message); |
| 593 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var(msg)); | 593 |
| 594 Log(msg); |
| 594 } | 595 } |
| 595 | 596 |
| 596 void VideoEncoderInstance::Log(const std::string& message) { | 597 void VideoEncoderInstance::Log(const std::string& message) { |
| 597 LogToConsole(PP_LOGLEVEL_LOG, pp::Var(message)); | 598 pp::VarDictionary dictionary; |
| 599 dictionary.Set(pp::Var("name"), pp::Var("log")); |
| 600 dictionary.Set(pp::Var("message"), pp::Var(message)); |
| 601 |
| 602 PostMessage(dictionary); |
| 598 } | 603 } |
| 599 | 604 |
| 600 pp::Instance* VideoEncoderModule::CreateInstance(PP_Instance instance) { | 605 pp::Instance* VideoEncoderModule::CreateInstance(PP_Instance instance) { |
| 601 return new VideoEncoderInstance(instance, this); | 606 return new VideoEncoderInstance(instance, this); |
| 602 } | 607 } |
| 603 | 608 |
| 604 } // anonymous namespace | 609 } // anonymous namespace |
| 605 | 610 |
| 606 namespace pp { | 611 namespace pp { |
| 607 // Factory function for your specialization of the Module object. | 612 // Factory function for your specialization of the Module object. |
| 608 Module* CreateModule() { | 613 Module* CreateModule() { |
| 609 return new VideoEncoderModule(); | 614 return new VideoEncoderModule(); |
| 610 } | 615 } |
| 611 } // namespace pp | 616 } // namespace pp |
| OLD | NEW |