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 |