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 <iostream> | 9 #include <iostream> |
| 10 #include <map> |
10 #include <sstream> | 11 #include <sstream> |
11 #include <vector> | 12 #include <vector> |
12 | 13 |
13 #include "ppapi/c/pp_errors.h" | 14 #include "ppapi/c/pp_errors.h" |
14 #include "ppapi/c/ppb_console.h" | 15 #include "ppapi/c/ppb_console.h" |
15 #include "ppapi/cpp/input_event.h" | 16 #include "ppapi/cpp/input_event.h" |
16 #include "ppapi/cpp/instance.h" | 17 #include "ppapi/cpp/instance.h" |
17 #include "ppapi/cpp/media_stream_video_track.h" | 18 #include "ppapi/cpp/media_stream_video_track.h" |
18 #include "ppapi/cpp/module.h" | 19 #include "ppapi/cpp/module.h" |
19 #include "ppapi/cpp/rect.h" | 20 #include "ppapi/cpp/rect.h" |
20 #include "ppapi/cpp/var.h" | 21 #include "ppapi/cpp/var.h" |
21 #include "ppapi/cpp/var_array_buffer.h" | 22 #include "ppapi/cpp/var_array_buffer.h" |
22 #include "ppapi/cpp/var_dictionary.h" | 23 #include "ppapi/cpp/var_dictionary.h" |
23 #include "ppapi/cpp/video_encoder.h" | 24 #include "ppapi/cpp/video_encoder.h" |
24 #include "ppapi/cpp/video_frame.h" | 25 #include "ppapi/cpp/video_frame.h" |
25 #include "ppapi/utility/completion_callback_factory.h" | 26 #include "ppapi/utility/completion_callback_factory.h" |
26 | 27 |
27 // TODO(llandwerlin): turn on by default when we have software encode. | |
28 // #define USE_VP8_INSTEAD_OF_H264 | |
29 | |
30 // When compiling natively on Windows, PostMessage can be #define-d to | 28 // When compiling natively on Windows, PostMessage can be #define-d to |
31 // something else. | 29 // something else. |
32 #ifdef PostMessage | 30 #ifdef PostMessage |
33 #undef PostMessage | 31 #undef PostMessage |
34 #endif | 32 #endif |
35 | 33 |
36 // Use assert as a poor-man's CHECK, even in non-debug mode. | 34 // Use assert as a poor-man's CHECK, even in non-debug mode. |
37 // Since <assert.h> redefines assert on every inclusion (it doesn't use | 35 // Since <assert.h> redefines assert on every inclusion (it doesn't use |
38 // include-guards), make sure this is the last file #include'd in this file. | 36 // include-guards), make sure this is the last file #include'd in this file. |
39 #undef NDEBUG | 37 #undef NDEBUG |
40 #include <assert.h> | 38 #include <assert.h> |
41 | 39 |
| 40 #define fourcc(a, b, c, d) \ |
| 41 (((uint32_t)(a) << 0) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | \ |
| 42 ((uint32_t)(d) << 24)) |
| 43 |
42 namespace { | 44 namespace { |
43 | 45 |
44 std::string VideoProfileToString(PP_VideoProfile profile) { | 46 // IVF container writer. It is possible to parse H264 bitstream using |
45 switch (profile) { | 47 // NAL units but for VP8 we need a container to at least find encoded |
46 case PP_VIDEOPROFILE_H264BASELINE: | 48 // pictures as well as the picture sizes. |
47 return "h264baseline"; | 49 class IVFWriter { |
48 case PP_VIDEOPROFILE_H264MAIN: | 50 public: |
49 return "h264main"; | 51 IVFWriter() {} |
50 case PP_VIDEOPROFILE_H264EXTENDED: | 52 ~IVFWriter() {} |
51 return "h264extended"; | 53 |
52 case PP_VIDEOPROFILE_H264HIGH: | 54 uint32_t GetFileHeaderSize() const { return 32; } |
53 return "h264high"; | 55 uint32_t GetFrameHeaderSize() const { return 12; } |
54 case PP_VIDEOPROFILE_H264HIGH10PROFILE: | 56 uint32_t WriteFileHeader(uint8_t* mem, int32_t width, int32_t height); |
55 return "h264high10"; | 57 uint32_t WriteFrameHeader(uint8_t* mem, uint64_t pts, size_t frame_size); |
56 case PP_VIDEOPROFILE_H264HIGH422PROFILE: | 58 |
57 return "h264high422"; | 59 private: |
58 case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE: | 60 void PutLE16(uint8_t* mem, int val) const { |
59 return "h264high444predictive"; | 61 mem[0] = (val >> 0) & 0xff; |
60 case PP_VIDEOPROFILE_H264SCALABLEBASELINE: | 62 mem[1] = (val >> 8) & 0xff; |
61 return "h264scalablebaseline"; | |
62 case PP_VIDEOPROFILE_H264SCALABLEHIGH: | |
63 return "h264scalablehigh"; | |
64 case PP_VIDEOPROFILE_H264STEREOHIGH: | |
65 return "h264stereohigh"; | |
66 case PP_VIDEOPROFILE_H264MULTIVIEWHIGH: | |
67 return "h264multiviewhigh"; | |
68 case PP_VIDEOPROFILE_VP8_ANY: | |
69 return "vp8"; | |
70 case PP_VIDEOPROFILE_VP9_ANY: | |
71 return "vp9"; | |
72 // No default to catch unhandled profiles. | |
73 } | 63 } |
74 return "unknown"; | 64 void PutLE32(uint8_t* mem, int val) const { |
| 65 mem[0] = (val >> 0) & 0xff; |
| 66 mem[1] = (val >> 8) & 0xff; |
| 67 mem[2] = (val >> 16) & 0xff; |
| 68 mem[3] = (val >> 24) & 0xff; |
| 69 } |
| 70 }; |
| 71 |
| 72 uint32_t IVFWriter::WriteFileHeader(uint8_t* mem, |
| 73 int32_t width, |
| 74 int32_t height) { |
| 75 mem[0] = 'D'; |
| 76 mem[1] = 'K'; |
| 77 mem[2] = 'I'; |
| 78 mem[3] = 'F'; |
| 79 PutLE16(mem + 4, 0); // version |
| 80 PutLE16(mem + 6, 32); // header size |
| 81 PutLE32(mem + 8, fourcc('V', 'P', '8', '0')); // fourcc |
| 82 PutLE16(mem + 12, static_cast<uint16_t>(width)); // width |
| 83 PutLE16(mem + 14, static_cast<uint16_t>(height)); // height |
| 84 PutLE32(mem + 16, 30); // rate |
| 85 PutLE32(mem + 20, 1); // scale |
| 86 PutLE32(mem + 24, 0xffffffff); // length |
| 87 PutLE32(mem + 28, 0); // unused |
| 88 |
| 89 return 32; |
75 } | 90 } |
76 | 91 |
77 std::string HardwareAccelerationToString(PP_HardwareAcceleration acceleration) { | 92 uint32_t IVFWriter::WriteFrameHeader(uint8_t* mem, |
78 switch (acceleration) { | 93 uint64_t pts, |
79 case PP_HARDWAREACCELERATION_ONLY: | 94 size_t frame_size) { |
80 return "hardware"; | 95 PutLE32(mem, (int)frame_size); |
81 case PP_HARDWAREACCELERATION_WITHFALLBACK: | 96 PutLE32(mem + 4, (int)(pts & 0xFFFFFFFF)); |
82 return "hardware/software"; | 97 PutLE32(mem + 8, (int)(pts >> 32)); |
83 case PP_HARDWAREACCELERATION_NONE: | 98 |
84 return "software"; | 99 return 12; |
85 // No default to catch unhandled accelerations. | |
86 } | |
87 return "unknown"; | |
88 } | 100 } |
89 | 101 |
90 // This object is the global object representing this plugin library as long | 102 // This object is the global object representing this plugin library as long |
91 // as it is loaded. | 103 // as it is loaded. |
92 class VideoEncoderModule : public pp::Module { | 104 class VideoEncoderModule : public pp::Module { |
93 public: | 105 public: |
94 VideoEncoderModule() : pp::Module() {} | 106 VideoEncoderModule() : pp::Module() {} |
95 virtual ~VideoEncoderModule() {} | 107 virtual ~VideoEncoderModule() {} |
96 | 108 |
97 virtual pp::Instance* CreateInstance(PP_Instance instance); | 109 virtual pp::Instance* CreateInstance(PP_Instance instance); |
98 }; | 110 }; |
99 | 111 |
100 class VideoEncoderInstance : public pp::Instance { | 112 class VideoEncoderInstance : public pp::Instance { |
101 public: | 113 public: |
102 VideoEncoderInstance(PP_Instance instance, pp::Module* module); | 114 VideoEncoderInstance(PP_Instance instance, pp::Module* module); |
103 virtual ~VideoEncoderInstance(); | 115 virtual ~VideoEncoderInstance(); |
104 | 116 |
105 // pp::Instance implementation. | 117 // pp::Instance implementation. |
106 virtual void HandleMessage(const pp::Var& var_message); | 118 virtual void HandleMessage(const pp::Var& var_message); |
107 | 119 |
108 private: | 120 private: |
| 121 void AddVideoProfile(PP_VideoProfile profile, const std::string& profile_str); |
| 122 void InitializeVideoProfiles(); |
| 123 PP_VideoProfile VideoProfileFromString(const std::string& str); |
| 124 std::string VideoProfileToString(PP_VideoProfile profile); |
| 125 |
109 void ConfigureTrack(); | 126 void ConfigureTrack(); |
110 void OnConfiguredTrack(int32_t result); | 127 void OnConfiguredTrack(int32_t result); |
111 void ProbeEncoder(); | 128 void ProbeEncoder(); |
112 void OnEncoderProbed(int32_t result, | 129 void OnEncoderProbed(int32_t result, |
113 const std::vector<PP_VideoProfileDescription> profiles); | 130 const std::vector<PP_VideoProfileDescription> profiles); |
| 131 void StartEncoder(); |
114 void OnInitializedEncoder(int32_t result); | 132 void OnInitializedEncoder(int32_t result); |
115 void ScheduleNextEncode(); | 133 void ScheduleNextEncode(); |
116 void GetEncoderFrameTick(int32_t result); | 134 void GetEncoderFrameTick(int32_t result); |
117 void GetEncoderFrame(const pp::VideoFrame& track_frame); | 135 void GetEncoderFrame(const pp::VideoFrame& track_frame); |
118 void OnEncoderFrame(int32_t result, | 136 void OnEncoderFrame(int32_t result, |
119 pp::VideoFrame encoder_frame, | 137 pp::VideoFrame encoder_frame, |
120 pp::VideoFrame track_frame); | 138 pp::VideoFrame track_frame); |
121 int32_t CopyVideoFrame(pp::VideoFrame dest, pp::VideoFrame src); | 139 int32_t CopyVideoFrame(pp::VideoFrame dest, pp::VideoFrame src); |
122 void EncodeFrame(const pp::VideoFrame& frame); | 140 void EncodeFrame(const pp::VideoFrame& frame); |
123 void OnEncodeDone(int32_t result); | 141 void OnEncodeDone(int32_t result); |
124 void OnGetBitstreamBuffer(int32_t result, PP_BitstreamBuffer buffer); | 142 void OnGetBitstreamBuffer(int32_t result, PP_BitstreamBuffer buffer); |
125 void StartTrackFrames(); | 143 void StartTrackFrames(); |
126 void StopTrackFrames(); | 144 void StopTrackFrames(); |
127 void OnTrackFrame(int32_t result, pp::VideoFrame frame); | 145 void OnTrackFrame(int32_t result, pp::VideoFrame frame); |
128 | 146 |
129 void StopEncode(); | 147 void StopEncode(); |
130 | 148 |
131 void LogError(int32_t error, const std::string& message); | 149 void LogError(int32_t error, const std::string& message); |
132 void Log(const std::string& message); | 150 void Log(const std::string& message); |
133 | 151 |
134 void PostDataMessage(const void* buffer, uint32_t size); | 152 void PostDataMessage(const void* buffer, uint32_t size); |
135 void PostSignalMessage(const char* name); | 153 void PostSignalMessage(const char* name); |
136 | 154 |
| 155 typedef std::map<std::string, PP_VideoProfile> VideoProfileFromStringMap; |
| 156 VideoProfileFromStringMap profile_from_string_; |
| 157 |
| 158 typedef std::map<PP_VideoProfile, std::string> VideoProfileToStringMap; |
| 159 VideoProfileToStringMap profile_to_string_; |
| 160 |
137 bool is_encoding_; | 161 bool is_encoding_; |
138 bool is_receiving_track_frames_; | 162 bool is_receiving_track_frames_; |
139 | 163 |
140 pp::VideoEncoder video_encoder_; | 164 pp::VideoEncoder video_encoder_; |
141 pp::MediaStreamVideoTrack video_track_; | 165 pp::MediaStreamVideoTrack video_track_; |
142 pp::CompletionCallbackFactory<VideoEncoderInstance> callback_factory_; | 166 pp::CompletionCallbackFactory<VideoEncoderInstance> callback_factory_; |
143 | 167 |
144 PP_VideoProfile video_profile_; | 168 PP_VideoProfile video_profile_; |
145 PP_VideoFrame_Format frame_format_; | 169 PP_VideoFrame_Format frame_format_; |
146 | 170 |
147 pp::Size requested_size_; | 171 pp::Size requested_size_; |
148 pp::Size frame_size_; | 172 pp::Size frame_size_; |
149 pp::Size encoder_size_; | 173 pp::Size encoder_size_; |
150 uint32_t encoded_frames_; | 174 uint32_t encoded_frames_; |
151 | 175 |
152 pp::VideoFrame current_track_frame_; | 176 pp::VideoFrame current_track_frame_; |
| 177 |
| 178 IVFWriter ivf_writer_; |
153 }; | 179 }; |
154 | 180 |
155 VideoEncoderInstance::VideoEncoderInstance(PP_Instance instance, | 181 VideoEncoderInstance::VideoEncoderInstance(PP_Instance instance, |
156 pp::Module* module) | 182 pp::Module* module) |
157 : pp::Instance(instance), | 183 : pp::Instance(instance), |
158 is_encoding_(false), | 184 is_encoding_(false), |
159 callback_factory_(this), | 185 callback_factory_(this), |
160 #if defined(USE_VP8_INSTEAD_OF_H264) | 186 #if defined(USE_VP8_INSTEAD_OF_H264) |
161 video_profile_(PP_VIDEOPROFILE_VP8_ANY), | 187 video_profile_(PP_VIDEOPROFILE_VP8_ANY), |
162 #else | 188 #else |
163 video_profile_(PP_VIDEOPROFILE_H264MAIN), | 189 video_profile_(PP_VIDEOPROFILE_H264MAIN), |
164 #endif | 190 #endif |
165 frame_format_(PP_VIDEOFRAME_FORMAT_I420), | 191 frame_format_(PP_VIDEOFRAME_FORMAT_I420), |
166 encoded_frames_(0) { | 192 encoded_frames_(0) { |
| 193 InitializeVideoProfiles(); |
| 194 ProbeEncoder(); |
167 } | 195 } |
168 | 196 |
169 VideoEncoderInstance::~VideoEncoderInstance() { | 197 VideoEncoderInstance::~VideoEncoderInstance() { |
170 } | 198 } |
171 | 199 |
| 200 void VideoEncoderInstance::AddVideoProfile(PP_VideoProfile profile, |
| 201 const std::string& profile_str) { |
| 202 profile_to_string_.insert(std::make_pair(profile, profile_str)); |
| 203 profile_from_string_.insert(std::make_pair(profile_str, profile)); |
| 204 } |
| 205 |
| 206 void VideoEncoderInstance::InitializeVideoProfiles() { |
| 207 AddVideoProfile(PP_VIDEOPROFILE_H264BASELINE, "h264baseline"); |
| 208 AddVideoProfile(PP_VIDEOPROFILE_H264MAIN, "h264main"); |
| 209 AddVideoProfile(PP_VIDEOPROFILE_H264EXTENDED, "h264extended"); |
| 210 AddVideoProfile(PP_VIDEOPROFILE_H264HIGH, "h264high"); |
| 211 AddVideoProfile(PP_VIDEOPROFILE_H264HIGH10PROFILE, "h264high10"); |
| 212 AddVideoProfile(PP_VIDEOPROFILE_H264HIGH422PROFILE, "h264high422"); |
| 213 AddVideoProfile(PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE, |
| 214 "h264high444predictive"); |
| 215 AddVideoProfile(PP_VIDEOPROFILE_H264SCALABLEBASELINE, "h264scalablebaseline"); |
| 216 AddVideoProfile(PP_VIDEOPROFILE_H264SCALABLEHIGH, "h264scalablehigh"); |
| 217 AddVideoProfile(PP_VIDEOPROFILE_H264STEREOHIGH, "h264stereohigh"); |
| 218 AddVideoProfile(PP_VIDEOPROFILE_H264MULTIVIEWHIGH, "h264multiviewhigh"); |
| 219 AddVideoProfile(PP_VIDEOPROFILE_VP8_ANY, "vp8"); |
| 220 AddVideoProfile(PP_VIDEOPROFILE_VP9_ANY, "vp9"); |
| 221 } |
| 222 |
| 223 PP_VideoProfile VideoEncoderInstance::VideoProfileFromString( |
| 224 const std::string& str) { |
| 225 VideoProfileFromStringMap::iterator it = profile_from_string_.find(str); |
| 226 if (it == profile_from_string_.end()) |
| 227 return PP_VIDEOPROFILE_VP8_ANY; |
| 228 return it->second; |
| 229 } |
| 230 |
| 231 std::string VideoEncoderInstance::VideoProfileToString( |
| 232 PP_VideoProfile profile) { |
| 233 VideoProfileToStringMap::iterator it = profile_to_string_.find(profile); |
| 234 if (it == profile_to_string_.end()) |
| 235 return "unknown"; |
| 236 return it->second; |
| 237 } |
| 238 |
172 void VideoEncoderInstance::ConfigureTrack() { | 239 void VideoEncoderInstance::ConfigureTrack() { |
173 if (encoder_size_.IsEmpty()) | 240 if (encoder_size_.IsEmpty()) |
174 frame_size_ = requested_size_; | 241 frame_size_ = requested_size_; |
175 else | 242 else |
176 frame_size_ = encoder_size_; | 243 frame_size_ = encoder_size_; |
177 | 244 |
178 int32_t attrib_list[] = {PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, | 245 int32_t attrib_list[] = {PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, |
179 frame_format_, | 246 frame_format_, |
180 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, | 247 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, |
181 frame_size_.width(), | 248 frame_size_.width(), |
(...skipping 15 matching lines...) Expand all Loading... |
197 void VideoEncoderInstance::OnConfiguredTrack(int32_t result) { | 264 void VideoEncoderInstance::OnConfiguredTrack(int32_t result) { |
198 if (result != PP_OK) { | 265 if (result != PP_OK) { |
199 LogError(result, "Cannot configure track"); | 266 LogError(result, "Cannot configure track"); |
200 return; | 267 return; |
201 } | 268 } |
202 | 269 |
203 if (is_encoding_) { | 270 if (is_encoding_) { |
204 StartTrackFrames(); | 271 StartTrackFrames(); |
205 ScheduleNextEncode(); | 272 ScheduleNextEncode(); |
206 } else | 273 } else |
207 ProbeEncoder(); | 274 StartEncoder(); |
208 } | 275 } |
209 | 276 |
210 void VideoEncoderInstance::ProbeEncoder() { | 277 void VideoEncoderInstance::ProbeEncoder() { |
211 video_encoder_ = pp::VideoEncoder(this); | 278 video_encoder_ = pp::VideoEncoder(this); |
212 video_encoder_.GetSupportedProfiles(callback_factory_.NewCallbackWithOutput( | 279 video_encoder_.GetSupportedProfiles(callback_factory_.NewCallbackWithOutput( |
213 &VideoEncoderInstance::OnEncoderProbed)); | 280 &VideoEncoderInstance::OnEncoderProbed)); |
214 } | 281 } |
215 | 282 |
216 void VideoEncoderInstance::OnEncoderProbed( | 283 void VideoEncoderInstance::OnEncoderProbed( |
217 int32_t result, | 284 int32_t result, |
218 const std::vector<PP_VideoProfileDescription> profiles) { | 285 const std::vector<PP_VideoProfileDescription> profiles) { |
219 bool has_required_profile = false; | 286 pp::VarDictionary dict; |
| 287 dict.Set(pp::Var("name"), pp::Var("supportedProfiles")); |
| 288 pp::VarArray js_profiles; |
| 289 dict.Set(pp::Var("profiles"), js_profiles); |
220 | 290 |
221 Log("Available profiles:"); | 291 if (result != PP_OK) { |
222 for (const PP_VideoProfileDescription& profile : profiles) { | 292 LogError(result, "Cannot get supported profiles"); |
223 std::ostringstream oss; | 293 PostMessage(dict); |
224 oss << " profile=" << VideoProfileToString(profile.profile) | |
225 << " max_resolution=" << profile.max_resolution.width << "x" | |
226 << profile.max_resolution.height | |
227 << " max_framerate=" << profile.max_framerate_numerator << "/" | |
228 << profile.max_framerate_denominator << " acceleration=" | |
229 << HardwareAccelerationToString(profile.acceleration); | |
230 Log(oss.str()); | |
231 | |
232 has_required_profile |= profile.profile == video_profile_; | |
233 } | 294 } |
234 | 295 |
235 if (!has_required_profile) { | 296 int32_t idx = 0; |
236 std::ostringstream oss; | 297 for (const PP_VideoProfileDescription& profile : profiles) |
237 oss << "Cannot find required video profile: "; | 298 js_profiles.Set(idx++, pp::Var(VideoProfileToString(profile.profile))); |
238 oss << VideoProfileToString(video_profile_); | 299 PostMessage(dict); |
239 LogError(PP_ERROR_FAILED, oss.str()); | 300 } |
240 return; | |
241 } | |
242 | 301 |
| 302 void VideoEncoderInstance::StartEncoder() { |
243 video_encoder_ = pp::VideoEncoder(this); | 303 video_encoder_ = pp::VideoEncoder(this); |
244 | 304 |
245 pp::VarDictionary dict; | |
246 dict.Set(pp::Var("status"), pp::Var("initializing encoder")); | |
247 dict.Set(pp::Var("width"), pp::Var(encoder_size_.width())); | |
248 dict.Set(pp::Var("height"), pp::Var(encoder_size_.height())); | |
249 PostMessage(dict); | |
250 | |
251 int32_t error = video_encoder_.Initialize( | 305 int32_t error = video_encoder_.Initialize( |
252 frame_format_, frame_size_, video_profile_, 2000000, | 306 frame_format_, frame_size_, video_profile_, 2000000, |
253 PP_HARDWAREACCELERATION_WITHFALLBACK, | 307 PP_HARDWAREACCELERATION_WITHFALLBACK, |
254 callback_factory_.NewCallback( | 308 callback_factory_.NewCallback( |
255 &VideoEncoderInstance::OnInitializedEncoder)); | 309 &VideoEncoderInstance::OnInitializedEncoder)); |
256 if (error != PP_OK_COMPLETIONPENDING) { | 310 if (error != PP_OK_COMPLETIONPENDING) { |
257 LogError(error, "Cannot initialize encoder"); | 311 LogError(error, "Cannot initialize encoder"); |
258 return; | 312 return; |
259 } | 313 } |
260 } | 314 } |
261 | 315 |
262 void VideoEncoderInstance::OnInitializedEncoder(int32_t result) { | 316 void VideoEncoderInstance::OnInitializedEncoder(int32_t result) { |
263 if (result != PP_OK) { | 317 if (result != PP_OK) { |
264 LogError(result, "Encoder initialization failed"); | 318 LogError(result, "Encoder initialization failed"); |
265 return; | 319 return; |
266 } | 320 } |
267 | 321 |
268 is_encoding_ = true; | 322 is_encoding_ = true; |
| 323 PostSignalMessage("started"); |
269 | 324 |
270 if (video_encoder_.GetFrameCodedSize(&encoder_size_) != PP_OK) { | 325 if (video_encoder_.GetFrameCodedSize(&encoder_size_) != PP_OK) { |
271 LogError(result, "Cannot get encoder coded frame size"); | 326 LogError(result, "Cannot get encoder coded frame size"); |
272 return; | 327 return; |
273 } | 328 } |
274 | 329 |
275 pp::VarDictionary dict; | |
276 dict.Set(pp::Var("status"), pp::Var("encoder initialized")); | |
277 dict.Set(pp::Var("width"), pp::Var(encoder_size_.width())); | |
278 dict.Set(pp::Var("height"), pp::Var(encoder_size_.height())); | |
279 PostMessage(dict); | |
280 | |
281 video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput( | 330 video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput( |
282 &VideoEncoderInstance::OnGetBitstreamBuffer)); | 331 &VideoEncoderInstance::OnGetBitstreamBuffer)); |
283 | 332 |
284 if (encoder_size_ != frame_size_) | 333 if (encoder_size_ != frame_size_) |
285 ConfigureTrack(); | 334 ConfigureTrack(); |
286 else { | 335 else { |
287 StartTrackFrames(); | 336 StartTrackFrames(); |
288 ScheduleNextEncode(); | 337 ScheduleNextEncode(); |
289 } | 338 } |
290 } | 339 } |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 int32_t VideoEncoderInstance::CopyVideoFrame(pp::VideoFrame dest, | 390 int32_t VideoEncoderInstance::CopyVideoFrame(pp::VideoFrame dest, |
342 pp::VideoFrame src) { | 391 pp::VideoFrame src) { |
343 if (dest.GetDataBufferSize() < src.GetDataBufferSize()) { | 392 if (dest.GetDataBufferSize() < src.GetDataBufferSize()) { |
344 std::ostringstream oss; | 393 std::ostringstream oss; |
345 oss << "Incorrect destination video frame buffer size : " | 394 oss << "Incorrect destination video frame buffer size : " |
346 << dest.GetDataBufferSize() << " < " << src.GetDataBufferSize(); | 395 << dest.GetDataBufferSize() << " < " << src.GetDataBufferSize(); |
347 LogError(PP_ERROR_FAILED, oss.str()); | 396 LogError(PP_ERROR_FAILED, oss.str()); |
348 return PP_ERROR_FAILED; | 397 return PP_ERROR_FAILED; |
349 } | 398 } |
350 | 399 |
| 400 dest.SetTimestamp(src.GetTimestamp()); |
351 memcpy(dest.GetDataBuffer(), src.GetDataBuffer(), src.GetDataBufferSize()); | 401 memcpy(dest.GetDataBuffer(), src.GetDataBuffer(), src.GetDataBufferSize()); |
352 return PP_OK; | 402 return PP_OK; |
353 } | 403 } |
354 | 404 |
355 void VideoEncoderInstance::EncodeFrame(const pp::VideoFrame& frame) { | 405 void VideoEncoderInstance::EncodeFrame(const pp::VideoFrame& frame) { |
356 video_encoder_.Encode( | 406 video_encoder_.Encode( |
357 frame, PP_FALSE, | 407 frame, PP_FALSE, |
358 callback_factory_.NewCallback(&VideoEncoderInstance::OnEncodeDone)); | 408 callback_factory_.NewCallback(&VideoEncoderInstance::OnEncodeDone)); |
359 } | 409 } |
360 | 410 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 requested_size_ = pp::Size(dict_message.Get("width").AsInt(), | 489 requested_size_ = pp::Size(dict_message.Get("width").AsInt(), |
440 dict_message.Get("height").AsInt()); | 490 dict_message.Get("height").AsInt()); |
441 pp::Var var_track = dict_message.Get("track"); | 491 pp::Var var_track = dict_message.Get("track"); |
442 if (!var_track.is_resource()) { | 492 if (!var_track.is_resource()) { |
443 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Given track is not a resource")); | 493 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Given track is not a resource")); |
444 return; | 494 return; |
445 } | 495 } |
446 pp::Resource resource_track = var_track.AsResource(); | 496 pp::Resource resource_track = var_track.AsResource(); |
447 video_track_ = pp::MediaStreamVideoTrack(resource_track); | 497 video_track_ = pp::MediaStreamVideoTrack(resource_track); |
448 video_encoder_ = pp::VideoEncoder(); | 498 video_encoder_ = pp::VideoEncoder(); |
| 499 video_profile_ = VideoProfileFromString( |
| 500 dict_message.Get("profile").AsString()); |
449 ConfigureTrack(); | 501 ConfigureTrack(); |
450 } else if (command == "stop") { | 502 } else if (command == "stop") { |
451 StopEncode(); | 503 StopEncode(); |
452 PostSignalMessage("stopped"); | 504 PostSignalMessage("stopped"); |
453 } else { | 505 } else { |
454 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!")); | 506 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!")); |
455 } | 507 } |
456 } | 508 } |
457 | 509 |
458 void VideoEncoderInstance::PostDataMessage(const void* buffer, uint32_t size) { | 510 void VideoEncoderInstance::PostDataMessage(const void* buffer, uint32_t size) { |
459 pp::VarDictionary dictionary; | 511 pp::VarDictionary dictionary; |
460 | 512 |
461 dictionary.Set(pp::Var("name"), pp::Var("data")); | 513 dictionary.Set(pp::Var("name"), pp::Var("data")); |
462 | 514 |
463 pp::VarArrayBuffer array_buffer(size); | 515 pp::VarArrayBuffer array_buffer; |
464 void* data_ptr = array_buffer.Map(); | 516 uint8_t* data_ptr; |
465 memcpy(data_ptr, buffer, size); | 517 uint32_t data_offset = 0; |
| 518 if (video_profile_ == PP_VIDEOPROFILE_VP8_ANY || |
| 519 video_profile_ == PP_VIDEOPROFILE_VP9_ANY) { |
| 520 uint32_t frame_offset = 0; |
| 521 if (encoded_frames_ == 1) { |
| 522 array_buffer = pp::VarArrayBuffer( |
| 523 size + ivf_writer_.GetFileHeaderSize() + |
| 524 ivf_writer_.GetFrameHeaderSize()); |
| 525 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); |
| 526 frame_offset = ivf_writer_.WriteFileHeader( |
| 527 data_ptr, frame_size_.width(), frame_size_.height()); |
| 528 } else { |
| 529 array_buffer = pp::VarArrayBuffer( |
| 530 size + ivf_writer_.GetFrameHeaderSize()); |
| 531 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); |
| 532 } |
| 533 data_offset = frame_offset + |
| 534 ivf_writer_.WriteFrameHeader(data_ptr + frame_offset, |
| 535 encoded_frames_, |
| 536 size); |
| 537 } else { |
| 538 array_buffer = pp::VarArrayBuffer(size); |
| 539 data_ptr = static_cast<uint8_t*>(array_buffer.Map()); |
| 540 } |
| 541 |
| 542 memcpy(data_ptr + data_offset, buffer, size); |
466 array_buffer.Unmap(); | 543 array_buffer.Unmap(); |
467 dictionary.Set(pp::Var("data"), array_buffer); | 544 dictionary.Set(pp::Var("data"), array_buffer); |
468 | 545 |
469 PostMessage(dictionary); | 546 PostMessage(dictionary); |
470 } | 547 } |
471 | 548 |
472 void VideoEncoderInstance::PostSignalMessage(const char* name) { | 549 void VideoEncoderInstance::PostSignalMessage(const char* name) { |
473 pp::VarDictionary dictionary; | 550 pp::VarDictionary dictionary; |
474 dictionary.Set(pp::Var("name"), pp::Var(name)); | 551 dictionary.Set(pp::Var("name"), pp::Var(name)); |
475 | 552 |
(...skipping 17 matching lines...) Expand all Loading... |
493 } | 570 } |
494 | 571 |
495 } // anonymous namespace | 572 } // anonymous namespace |
496 | 573 |
497 namespace pp { | 574 namespace pp { |
498 // Factory function for your specialization of the Module object. | 575 // Factory function for your specialization of the Module object. |
499 Module* CreateModule() { | 576 Module* CreateModule() { |
500 return new VideoEncoderModule(); | 577 return new VideoEncoderModule(); |
501 } | 578 } |
502 } // namespace pp | 579 } // namespace pp |
OLD | NEW |