OLD | NEW |
---|---|
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 11 matching lines...) Expand all Loading... | |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 * | 26 * |
27 */ | 27 */ |
28 | 28 |
29 #include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h" | 29 #include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h" |
30 #include "talk/app/webrtc/java/jni/classreferenceholder.h" | 30 #include "talk/app/webrtc/java/jni/classreferenceholder.h" |
31 #include "talk/app/webrtc/java/jni/androidmediacodeccommon.h" | 31 #include "talk/app/webrtc/java/jni/androidmediacodeccommon.h" |
32 #include "talk/app/webrtc/java/jni/native_handle_impl.h" | |
32 #include "webrtc/base/bind.h" | 33 #include "webrtc/base/bind.h" |
33 #include "webrtc/base/checks.h" | 34 #include "webrtc/base/checks.h" |
34 #include "webrtc/base/logging.h" | 35 #include "webrtc/base/logging.h" |
35 #include "webrtc/base/thread.h" | 36 #include "webrtc/base/thread.h" |
36 #include "webrtc/base/thread_checker.h" | 37 #include "webrtc/base/thread_checker.h" |
37 #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h" | 38 #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h" |
38 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" | 39 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" |
39 #include "webrtc/modules/video_coding/utility/include/quality_scaler.h" | 40 #include "webrtc/modules/video_coding/utility/include/quality_scaler.h" |
40 #include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h" | 41 #include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h" |
41 #include "webrtc/system_wrappers/interface/field_trial.h" | 42 #include "webrtc/system_wrappers/interface/field_trial.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 // Android's MediaCodec SDK API behind the scenes to implement (hopefully) | 75 // Android's MediaCodec SDK API behind the scenes to implement (hopefully) |
75 // HW-backed video encode. This C++ class is implemented as a very thin shim, | 76 // HW-backed video encode. This C++ class is implemented as a very thin shim, |
76 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder. | 77 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder. |
77 // MediaCodecVideoEncoder is created, operated, and destroyed on a single | 78 // MediaCodecVideoEncoder is created, operated, and destroyed on a single |
78 // thread, currently the libjingle Worker thread. | 79 // thread, currently the libjingle Worker thread. |
79 class MediaCodecVideoEncoder : public webrtc::VideoEncoder, | 80 class MediaCodecVideoEncoder : public webrtc::VideoEncoder, |
80 public rtc::MessageHandler { | 81 public rtc::MessageHandler { |
81 public: | 82 public: |
82 virtual ~MediaCodecVideoEncoder(); | 83 virtual ~MediaCodecVideoEncoder(); |
83 MediaCodecVideoEncoder(JNIEnv* jni, | 84 MediaCodecVideoEncoder(JNIEnv* jni, |
84 VideoCodecType codecType); | 85 VideoCodecType codecType, |
86 jobject egl_context); | |
85 | 87 |
86 // webrtc::VideoEncoder implementation. Everything trampolines to | 88 // webrtc::VideoEncoder implementation. Everything trampolines to |
87 // |codec_thread_| for execution. | 89 // |codec_thread_| for execution. |
88 int32_t InitEncode(const webrtc::VideoCodec* codec_settings, | 90 int32_t InitEncode(const webrtc::VideoCodec* codec_settings, |
89 int32_t /* number_of_cores */, | 91 int32_t /* number_of_cores */, |
90 size_t /* max_payload_size */) override; | 92 size_t /* max_payload_size */) override; |
91 int32_t Encode( | 93 int32_t Encode( |
92 const webrtc::VideoFrame& input_image, | 94 const webrtc::VideoFrame& input_image, |
93 const webrtc::CodecSpecificInfo* /* codec_specific_info */, | 95 const webrtc::CodecSpecificInfo* /* codec_specific_info */, |
94 const std::vector<webrtc::VideoFrameType>* frame_types) override; | 96 const std::vector<webrtc::VideoFrameType>* frame_types) override; |
95 int32_t RegisterEncodeCompleteCallback( | 97 int32_t RegisterEncodeCompleteCallback( |
96 webrtc::EncodedImageCallback* callback) override; | 98 webrtc::EncodedImageCallback* callback) override; |
97 int32_t Release() override; | 99 int32_t Release() override; |
98 int32_t SetChannelParameters(uint32_t /* packet_loss */, | 100 int32_t SetChannelParameters(uint32_t /* packet_loss */, |
99 int64_t /* rtt */) override; | 101 int64_t /* rtt */) override; |
100 int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) override; | 102 int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) override; |
101 | 103 |
102 // rtc::MessageHandler implementation. | 104 // rtc::MessageHandler implementation. |
103 void OnMessage(rtc::Message* msg) override; | 105 void OnMessage(rtc::Message* msg) override; |
104 | 106 |
105 void OnDroppedFrame() override; | 107 void OnDroppedFrame() override; |
106 | 108 |
107 int GetTargetFramerate() override; | 109 int GetTargetFramerate() override; |
108 | 110 |
111 bool SupportsNativeHandle() const override { return true; } | |
112 | |
109 private: | 113 private: |
110 // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and | 114 // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and |
111 // InitEncodeOnCodecThread() in an attempt to restore the codec to an | 115 // InitEncodeOnCodecThread() in an attempt to restore the codec to an |
112 // operable state. Necessary after all manner of OMX-layer errors. | 116 // operable state. Necessary after all manner of OMX-layer errors. |
113 void ResetCodecOnCodecThread(); | 117 void ResetCodecOnCodecThread(); |
114 | 118 |
115 // Implementation of webrtc::VideoEncoder methods above, all running on the | 119 // Implementation of webrtc::VideoEncoder methods above, all running on the |
116 // codec thread exclusively. | 120 // codec thread exclusively. |
117 // | 121 // |
118 // If width==0 then this is assumed to be a re-initialization and the | 122 // If width==0 then this is assumed to be a re-initialization and the |
119 // previously-current values are reused instead of the passed parameters | 123 // previously-current values are reused instead of the passed parameters |
120 // (makes it easier to reason about thread-safety). | 124 // (makes it easier to reason about thread-safety). |
121 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps); | 125 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps, |
122 // Reconfigure to match |frame| in width, height. Returns false if | 126 bool use_surface); |
123 // reconfiguring fails. | 127 // Reconfigure to match |frame| in width, height. Also reconfigures the |
128 // encoder if |frame| is a texture/byte buffer and the encoder is initialized | |
129 // for byte buffer/texture. Returns false if reconfiguring fails. | |
124 bool MaybeReconfigureEncoderOnCodecThread(const webrtc::VideoFrame& frame); | 130 bool MaybeReconfigureEncoderOnCodecThread(const webrtc::VideoFrame& frame); |
125 int32_t EncodeOnCodecThread( | 131 int32_t EncodeOnCodecThread( |
126 const webrtc::VideoFrame& input_image, | 132 const webrtc::VideoFrame& input_image, |
127 const std::vector<webrtc::VideoFrameType>* frame_types); | 133 const std::vector<webrtc::VideoFrameType>* frame_types); |
128 bool EncodeByteBufferOnCodecThread(JNIEnv* jni, | 134 bool EncodeByteBufferOnCodecThread(JNIEnv* jni, |
129 bool key_frame, const webrtc::VideoFrame& frame); | 135 bool key_frame, const webrtc::VideoFrame& frame); |
136 bool EncodeTextureOnCodecThread(JNIEnv* jni, | |
137 bool key_frame, const webrtc::VideoFrame& frame); | |
130 | 138 |
131 int32_t RegisterEncodeCompleteCallbackOnCodecThread( | 139 int32_t RegisterEncodeCompleteCallbackOnCodecThread( |
132 webrtc::EncodedImageCallback* callback); | 140 webrtc::EncodedImageCallback* callback); |
133 int32_t ReleaseOnCodecThread(); | 141 int32_t ReleaseOnCodecThread(); |
134 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate); | 142 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate); |
135 | 143 |
136 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members. | 144 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members. |
137 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info); | 145 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info); |
138 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info); | 146 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info); |
139 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info); | 147 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info); |
(...skipping 17 matching lines...) Expand all Loading... | |
157 // State that is constant for the lifetime of this object once the ctor | 165 // State that is constant for the lifetime of this object once the ctor |
158 // returns. | 166 // returns. |
159 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. | 167 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. |
160 rtc::ThreadChecker codec_thread_checker_; | 168 rtc::ThreadChecker codec_thread_checker_; |
161 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_; | 169 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_; |
162 ScopedGlobalRef<jobject> j_media_codec_video_encoder_; | 170 ScopedGlobalRef<jobject> j_media_codec_video_encoder_; |
163 jmethodID j_init_encode_method_; | 171 jmethodID j_init_encode_method_; |
164 jmethodID j_get_input_buffers_method_; | 172 jmethodID j_get_input_buffers_method_; |
165 jmethodID j_dequeue_input_buffer_method_; | 173 jmethodID j_dequeue_input_buffer_method_; |
166 jmethodID j_encode_buffer_method_; | 174 jmethodID j_encode_buffer_method_; |
175 jmethodID j_encode_texture_method_; | |
167 jmethodID j_release_method_; | 176 jmethodID j_release_method_; |
168 jmethodID j_set_rates_method_; | 177 jmethodID j_set_rates_method_; |
169 jmethodID j_dequeue_output_buffer_method_; | 178 jmethodID j_dequeue_output_buffer_method_; |
170 jmethodID j_release_output_buffer_method_; | 179 jmethodID j_release_output_buffer_method_; |
171 jfieldID j_color_format_field_; | 180 jfieldID j_color_format_field_; |
172 jfieldID j_info_index_field_; | 181 jfieldID j_info_index_field_; |
173 jfieldID j_info_buffer_field_; | 182 jfieldID j_info_buffer_field_; |
174 jfieldID j_info_is_key_frame_field_; | 183 jfieldID j_info_is_key_frame_field_; |
175 jfieldID j_info_presentation_timestamp_us_field_; | 184 jfieldID j_info_presentation_timestamp_us_field_; |
176 | 185 |
177 // State that is valid only between InitEncode() and the next Release(). | 186 // State that is valid only between InitEncode() and the next Release(). |
178 // Touched only on codec_thread_ so no explicit synchronization necessary. | 187 // Touched only on codec_thread_ so no explicit synchronization necessary. |
179 int width_; // Frame width in pixels. | 188 int width_; // Frame width in pixels. |
180 int height_; // Frame height in pixels. | 189 int height_; // Frame height in pixels. |
181 bool inited_; | 190 bool inited_; |
191 bool use_surface_; | |
182 uint16_t picture_id_; | 192 uint16_t picture_id_; |
183 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format. | 193 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format. |
184 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps. | 194 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps. |
185 int last_set_fps_; // Last-requested frame rate. | 195 int last_set_fps_; // Last-requested frame rate. |
186 int64_t current_timestamp_us_; // Current frame timestamps in us. | 196 int64_t current_timestamp_us_; // Current frame timestamps in us. |
187 int frames_received_; // Number of frames received by encoder. | 197 int frames_received_; // Number of frames received by encoder. |
188 int frames_encoded_; // Number of frames encoded by encoder. | 198 int frames_encoded_; // Number of frames encoded by encoder. |
189 int frames_dropped_; // Number of frames dropped by encoder. | 199 int frames_dropped_; // Number of frames dropped by encoder. |
190 int frames_in_queue_; // Number of frames in encoder queue. | 200 int frames_in_queue_; // Number of frames in encoder queue. |
191 int64_t start_time_ms_; // Start time for statistics. | 201 int64_t start_time_ms_; // Start time for statistics. |
(...skipping 15 matching lines...) Expand all Loading... | |
207 // and the next Encode() call being ignored. | 217 // and the next Encode() call being ignored. |
208 bool drop_next_input_frame_; | 218 bool drop_next_input_frame_; |
209 // Global references; must be deleted in Release(). | 219 // Global references; must be deleted in Release(). |
210 std::vector<jobject> input_buffers_; | 220 std::vector<jobject> input_buffers_; |
211 webrtc::QualityScaler quality_scaler_; | 221 webrtc::QualityScaler quality_scaler_; |
212 // Dynamic resolution change, off by default. | 222 // Dynamic resolution change, off by default. |
213 bool scale_; | 223 bool scale_; |
214 | 224 |
215 // H264 bitstream parser, used to extract QP from encoded bitstreams. | 225 // H264 bitstream parser, used to extract QP from encoded bitstreams. |
216 webrtc::H264BitstreamParser h264_bitstream_parser_; | 226 webrtc::H264BitstreamParser h264_bitstream_parser_; |
227 | |
228 // EGL context - owned by factory, should not be allocated/destroyed | |
229 // by MediaCodecVideoEncoder. | |
230 jobject egl_context_; | |
217 }; | 231 }; |
218 | 232 |
219 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { | 233 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { |
220 // Call Release() to ensure no more callbacks to us after we are deleted. | 234 // Call Release() to ensure no more callbacks to us after we are deleted. |
221 Release(); | 235 Release(); |
222 } | 236 } |
223 | 237 |
224 MediaCodecVideoEncoder::MediaCodecVideoEncoder( | 238 MediaCodecVideoEncoder::MediaCodecVideoEncoder( |
225 JNIEnv* jni, VideoCodecType codecType) : | 239 JNIEnv* jni, VideoCodecType codecType, jobject egl_context) : |
226 codecType_(codecType), | 240 codecType_(codecType), |
227 callback_(NULL), | 241 callback_(NULL), |
228 inited_(false), | 242 inited_(false), |
243 use_surface_(false), | |
229 picture_id_(0), | 244 picture_id_(0), |
230 codec_thread_(new Thread()), | 245 codec_thread_(new Thread()), |
231 j_media_codec_video_encoder_class_( | 246 j_media_codec_video_encoder_class_( |
232 jni, | 247 jni, |
233 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")), | 248 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")), |
234 j_media_codec_video_encoder_( | 249 j_media_codec_video_encoder_( |
235 jni, | 250 jni, |
236 jni->NewObject(*j_media_codec_video_encoder_class_, | 251 jni->NewObject(*j_media_codec_video_encoder_class_, |
237 GetMethodID(jni, | 252 GetMethodID(jni, |
238 *j_media_codec_video_encoder_class_, | 253 *j_media_codec_video_encoder_class_, |
239 "<init>", | 254 "<init>", |
240 "()V"))) { | 255 "()V"))), |
256 egl_context_(egl_context) { | |
241 ScopedLocalRefFrame local_ref_frame(jni); | 257 ScopedLocalRefFrame local_ref_frame(jni); |
242 // It would be nice to avoid spinning up a new thread per MediaCodec, and | 258 // It would be nice to avoid spinning up a new thread per MediaCodec, and |
243 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug | 259 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug |
244 // 2732 means that deadlocks abound. This class synchronously trampolines | 260 // 2732 means that deadlocks abound. This class synchronously trampolines |
245 // to |codec_thread_|, so if anything else can be coming to _us_ from | 261 // to |codec_thread_|, so if anything else can be coming to _us_ from |
246 // |codec_thread_|, or from any thread holding the |_sendCritSect| described | 262 // |codec_thread_|, or from any thread holding the |_sendCritSect| described |
247 // in the bug, we have a problem. For now work around that with a dedicated | 263 // in the bug, we have a problem. For now work around that with a dedicated |
248 // thread. | 264 // thread. |
249 codec_thread_->SetName("MediaCodecVideoEncoder", NULL); | 265 codec_thread_->SetName("MediaCodecVideoEncoder", NULL); |
250 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; | 266 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; |
251 codec_thread_checker_.DetachFromThread(); | 267 codec_thread_checker_.DetachFromThread(); |
252 jclass j_output_buffer_info_class = | 268 jclass j_output_buffer_info_class = |
253 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo"); | 269 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo"); |
254 j_init_encode_method_ = GetMethodID( | 270 j_init_encode_method_ = GetMethodID( |
255 jni, | 271 jni, |
256 *j_media_codec_video_encoder_class_, | 272 *j_media_codec_video_encoder_class_, |
257 "initEncode", | 273 "initEncode", |
258 "(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;IIII)Z"); | 274 "(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;" |
275 "IIIILandroid/opengl/EGLContext;)Z"); | |
259 j_get_input_buffers_method_ = GetMethodID( | 276 j_get_input_buffers_method_ = GetMethodID( |
260 jni, | 277 jni, |
261 *j_media_codec_video_encoder_class_, | 278 *j_media_codec_video_encoder_class_, |
262 "getInputBuffers", | 279 "getInputBuffers", |
263 "()[Ljava/nio/ByteBuffer;"); | 280 "()[Ljava/nio/ByteBuffer;"); |
264 j_dequeue_input_buffer_method_ = GetMethodID( | 281 j_dequeue_input_buffer_method_ = GetMethodID( |
265 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I"); | 282 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I"); |
266 j_encode_buffer_method_ = GetMethodID( | 283 j_encode_buffer_method_ = GetMethodID( |
267 jni, *j_media_codec_video_encoder_class_, "encodeBuffer", "(ZIIJ)Z"); | 284 jni, *j_media_codec_video_encoder_class_, "encodeBuffer", "(ZIIJ)Z"); |
285 j_encode_texture_method_ = GetMethodID( | |
286 jni, *j_media_codec_video_encoder_class_, "encodeTexture", | |
287 "(ZI[FJ)Z"); | |
268 j_release_method_ = | 288 j_release_method_ = |
269 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V"); | 289 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V"); |
270 j_set_rates_method_ = GetMethodID( | 290 j_set_rates_method_ = GetMethodID( |
271 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z"); | 291 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z"); |
272 j_dequeue_output_buffer_method_ = GetMethodID( | 292 j_dequeue_output_buffer_method_ = GetMethodID( |
273 jni, | 293 jni, |
274 *j_media_codec_video_encoder_class_, | 294 *j_media_codec_video_encoder_class_, |
275 "dequeueOutputBuffer", | 295 "dequeueOutputBuffer", |
276 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;"); | 296 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;"); |
277 j_release_output_buffer_method_ = GetMethodID( | 297 j_release_output_buffer_method_ = GetMethodID( |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
337 } | 357 } |
338 quality_scaler_.SetMinResolution(kMinWidth, kMinHeight); | 358 quality_scaler_.SetMinResolution(kMinWidth, kMinHeight); |
339 quality_scaler_.ReportFramerate(codec_settings->maxFramerate); | 359 quality_scaler_.ReportFramerate(codec_settings->maxFramerate); |
340 } | 360 } |
341 return codec_thread_->Invoke<int32_t>( | 361 return codec_thread_->Invoke<int32_t>( |
342 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread, | 362 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread, |
343 this, | 363 this, |
344 codec_settings->width, | 364 codec_settings->width, |
345 codec_settings->height, | 365 codec_settings->height, |
346 codec_settings->startBitrate, | 366 codec_settings->startBitrate, |
347 codec_settings->maxFramerate)); | 367 codec_settings->maxFramerate, |
368 false /*use_surface*/)); | |
348 } | 369 } |
349 | 370 |
350 int32_t MediaCodecVideoEncoder::Encode( | 371 int32_t MediaCodecVideoEncoder::Encode( |
351 const webrtc::VideoFrame& frame, | 372 const webrtc::VideoFrame& frame, |
352 const webrtc::CodecSpecificInfo* /* codec_specific_info */, | 373 const webrtc::CodecSpecificInfo* /* codec_specific_info */, |
353 const std::vector<webrtc::VideoFrameType>* frame_types) { | 374 const std::vector<webrtc::VideoFrameType>* frame_types) { |
354 return codec_thread_->Invoke<int32_t>(Bind( | 375 return codec_thread_->Invoke<int32_t>(Bind( |
355 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types)); | 376 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types)); |
356 } | 377 } |
357 | 378 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
403 // unclear how to signal such a failure to the app, so instead we stay silent | 424 // unclear how to signal such a failure to the app, so instead we stay silent |
404 // about it and let the next app-called API method reveal the borkedness. | 425 // about it and let the next app-called API method reveal the borkedness. |
405 DeliverPendingOutputs(jni); | 426 DeliverPendingOutputs(jni); |
406 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | 427 codec_thread_->PostDelayed(kMediaCodecPollMs, this); |
407 } | 428 } |
408 | 429 |
409 void MediaCodecVideoEncoder::ResetCodecOnCodecThread() { | 430 void MediaCodecVideoEncoder::ResetCodecOnCodecThread() { |
410 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 431 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
411 ALOGE << "ResetOnCodecThread"; | 432 ALOGE << "ResetOnCodecThread"; |
412 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || | 433 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || |
413 InitEncodeOnCodecThread(width_, height_, 0, 0) | 434 InitEncodeOnCodecThread(width_, height_, 0, 0, |
414 != WEBRTC_VIDEO_CODEC_OK) { | 435 use_surface_) != WEBRTC_VIDEO_CODEC_OK) { |
AlexG
2015/10/14 23:48:27
false instead of use_surface_ so it will be simila
perkj_webrtc
2015/11/16 13:08:51
Done.
| |
415 // TODO(fischman): wouldn't it be nice if there was a way to gracefully | 436 // TODO(fischman): wouldn't it be nice if there was a way to gracefully |
416 // degrade to a SW encoder at this point? There isn't one AFAICT :( | 437 // degrade to a SW encoder at this point? There isn't one AFAICT :( |
417 // https://code.google.com/p/webrtc/issues/detail?id=2920 | 438 // https://code.google.com/p/webrtc/issues/detail?id=2920 |
418 } | 439 } |
419 } | 440 } |
420 | 441 |
421 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( | 442 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( |
422 int width, int height, int kbps, int fps) { | 443 int width, int height, int kbps, int fps, bool use_surface) { |
423 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 444 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
445 RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set."; | |
424 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 446 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
425 ScopedLocalRefFrame local_ref_frame(jni); | 447 ScopedLocalRefFrame local_ref_frame(jni); |
426 | 448 |
427 ALOGD << "InitEncodeOnCodecThread Type: " << (int)codecType_ << ", " << | 449 ALOGD << "InitEncodeOnCodecThread Type: " << (int)codecType_ << ", " << |
428 width << " x " << height << ". Bitrate: " << kbps << | 450 width << " x " << height << ". Bitrate: " << kbps << |
429 " kbps. Fps: " << fps; | 451 " kbps. Fps: " << fps; |
430 if (kbps == 0) { | 452 if (kbps == 0) { |
431 kbps = last_set_bitrate_kbps_; | 453 kbps = last_set_bitrate_kbps_; |
432 } | 454 } |
433 if (fps == 0) { | 455 if (fps == 0) { |
(...skipping 22 matching lines...) Expand all Loading... | |
456 render_times_ms_.clear(); | 478 render_times_ms_.clear(); |
457 frame_rtc_times_ms_.clear(); | 479 frame_rtc_times_ms_.clear(); |
458 drop_next_input_frame_ = false; | 480 drop_next_input_frame_ = false; |
459 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; | 481 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; |
460 | 482 |
461 // We enforce no extra stride/padding in the format creation step. | 483 // We enforce no extra stride/padding in the format creation step. |
462 jobject j_video_codec_enum = JavaEnumFromIndex( | 484 jobject j_video_codec_enum = JavaEnumFromIndex( |
463 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); | 485 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); |
464 const bool encode_status = jni->CallBooleanMethod( | 486 const bool encode_status = jni->CallBooleanMethod( |
465 *j_media_codec_video_encoder_, j_init_encode_method_, | 487 *j_media_codec_video_encoder_, j_init_encode_method_, |
466 j_video_codec_enum, width, height, kbps, fps); | 488 j_video_codec_enum, width, height, kbps, fps, |
489 (use_surface ? egl_context_ : nullptr)); | |
467 if (!encode_status) { | 490 if (!encode_status) { |
468 ALOGE << "Failed to configure encoder."; | 491 ALOGE << "Failed to configure encoder."; |
469 return WEBRTC_VIDEO_CODEC_ERROR; | 492 return WEBRTC_VIDEO_CODEC_ERROR; |
470 } | 493 } |
471 CHECK_EXCEPTION(jni); | 494 CHECK_EXCEPTION(jni); |
472 | 495 |
473 jobjectArray input_buffers = reinterpret_cast<jobjectArray>( | 496 if (use_surface) { |
474 jni->CallObjectMethod(*j_media_codec_video_encoder_, | 497 scale_ = false; // TODO(perkj): Implement scaling when using textures. |
475 j_get_input_buffers_method_)); | 498 use_surface_ = true; |
476 CHECK_EXCEPTION(jni); | 499 } else { |
477 if (IsNull(jni, input_buffers)) { | 500 jobjectArray input_buffers = reinterpret_cast<jobjectArray>( |
478 return WEBRTC_VIDEO_CODEC_ERROR; | 501 jni->CallObjectMethod(*j_media_codec_video_encoder_, |
502 j_get_input_buffers_method_)); | |
503 CHECK_EXCEPTION(jni); | |
504 if (IsNull(jni, input_buffers)) { | |
505 return WEBRTC_VIDEO_CODEC_ERROR; | |
506 } | |
507 | |
508 switch (GetIntField(jni, *j_media_codec_video_encoder_, | |
509 j_color_format_field_)) { | |
510 case COLOR_FormatYUV420Planar: | |
511 encoder_fourcc_ = libyuv::FOURCC_YU12; | |
512 break; | |
513 case COLOR_FormatYUV420SemiPlanar: | |
514 case COLOR_QCOM_FormatYUV420SemiPlanar: | |
515 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: | |
516 encoder_fourcc_ = libyuv::FOURCC_NV12; | |
517 break; | |
518 default: | |
519 LOG(LS_ERROR) << "Wrong color format."; | |
520 return WEBRTC_VIDEO_CODEC_ERROR; | |
521 } | |
522 size_t num_input_buffers = jni->GetArrayLength(input_buffers); | |
523 RTC_CHECK(input_buffers_.empty()) | |
524 << "Unexpected double InitEncode without Release"; | |
525 input_buffers_.resize(num_input_buffers); | |
526 for (size_t i = 0; i < num_input_buffers; ++i) { | |
527 input_buffers_[i] = | |
528 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); | |
529 int64_t yuv_buffer_capacity = | |
530 jni->GetDirectBufferCapacity(input_buffers_[i]); | |
531 CHECK_EXCEPTION(jni); | |
532 RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; | |
533 } | |
479 } | 534 } |
480 | 535 |
481 switch (GetIntField(jni, *j_media_codec_video_encoder_, | |
482 j_color_format_field_)) { | |
483 case COLOR_FormatYUV420Planar: | |
484 encoder_fourcc_ = libyuv::FOURCC_YU12; | |
485 break; | |
486 case COLOR_FormatYUV420SemiPlanar: | |
487 case COLOR_QCOM_FormatYUV420SemiPlanar: | |
488 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: | |
489 encoder_fourcc_ = libyuv::FOURCC_NV12; | |
490 break; | |
491 default: | |
492 LOG(LS_ERROR) << "Wrong color format."; | |
493 return WEBRTC_VIDEO_CODEC_ERROR; | |
494 } | |
495 size_t num_input_buffers = jni->GetArrayLength(input_buffers); | |
496 RTC_CHECK(input_buffers_.empty()) | |
497 << "Unexpected double InitEncode without Release"; | |
498 input_buffers_.resize(num_input_buffers); | |
499 for (size_t i = 0; i < num_input_buffers; ++i) { | |
500 input_buffers_[i] = | |
501 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); | |
502 int64_t yuv_buffer_capacity = | |
503 jni->GetDirectBufferCapacity(input_buffers_[i]); | |
504 CHECK_EXCEPTION(jni); | |
505 RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; | |
506 } | |
507 CHECK_EXCEPTION(jni); | |
508 | |
509 | |
510 inited_ = true; | 536 inited_ = true; |
511 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | 537 codec_thread_->PostDelayed(kMediaCodecPollMs, this); |
512 return WEBRTC_VIDEO_CODEC_OK; | 538 return WEBRTC_VIDEO_CODEC_OK; |
513 } | 539 } |
514 | 540 |
515 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( | 541 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
516 const webrtc::VideoFrame& frame, | 542 const webrtc::VideoFrame& frame, |
517 const std::vector<webrtc::VideoFrameType>* frame_types) { | 543 const std::vector<webrtc::VideoFrameType>* frame_types) { |
518 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 544 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
519 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 545 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
566 last_input_timestamp_ms_ = | 592 last_input_timestamp_ms_ = |
567 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; | 593 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; |
568 frames_in_queue_++; | 594 frames_in_queue_++; |
569 | 595 |
570 // Save input image timestamps for later output | 596 // Save input image timestamps for later output |
571 timestamps_.push_back(input_frame.timestamp()); | 597 timestamps_.push_back(input_frame.timestamp()); |
572 render_times_ms_.push_back(input_frame.render_time_ms()); | 598 render_times_ms_.push_back(input_frame.render_time_ms()); |
573 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); | 599 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); |
574 | 600 |
575 const bool key_frame = frame_types->front() != webrtc::kDeltaFrame; | 601 const bool key_frame = frame_types->front() != webrtc::kDeltaFrame; |
576 const bool encode_status = | 602 bool encode_status = true; |
577 EncodeByteBufferOnCodecThread(jni, key_frame, input_frame); | 603 if (input_frame.native_handle()) |
604 encode_status = EncodeTextureOnCodecThread(jni, key_frame, | |
605 input_frame); | |
AlexG
2015/10/14 23:48:27
nit: input_frame can fit previous line?
perkj_webrtc
2015/11/16 13:08:51
Done.
| |
606 else | |
607 encode_status = EncodeByteBufferOnCodecThread(jni, key_frame, input_frame); | |
578 | 608 |
579 current_timestamp_us_ += 1000000 / last_set_fps_; | 609 current_timestamp_us_ += 1000000 / last_set_fps_; |
580 | 610 |
581 if (!encode_status || !DeliverPendingOutputs(jni)) { | 611 if (!encode_status || !DeliverPendingOutputs(jni)) { |
582 ALOGE << "Failed deliver pending outputs."; | 612 ALOGE << "Failed deliver pending outputs."; |
583 ResetCodecOnCodecThread(); | 613 ResetCodecOnCodecThread(); |
584 return WEBRTC_VIDEO_CODEC_ERROR; | 614 return WEBRTC_VIDEO_CODEC_ERROR; |
585 } | 615 } |
586 return WEBRTC_VIDEO_CODEC_OK; | 616 return WEBRTC_VIDEO_CODEC_OK; |
587 } | 617 } |
588 | 618 |
589 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( | 619 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( |
590 const webrtc::VideoFrame& frame) { | 620 const webrtc::VideoFrame& frame) { |
591 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 621 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
592 | 622 |
593 const bool reconfigure_due_to_size = | 623 const bool is_texture_frame = frame.native_handle() != nullptr; |
624 const bool reconfigure_due_to_format = is_texture_frame != use_surface_; | |
625 bool reconfigure_due_to_size = | |
594 frame.width() != width_ || frame.height() != height_; | 626 frame.width() != width_ || frame.height() != height_; |
595 | 627 |
628 if (reconfigure_due_to_format) { | |
629 ALOGD << "Reconfigure encoder due to format change. " | |
630 << (use_surface_ ? | |
631 "Reconfiguring to encode from byte buffer." : | |
632 "Reconfiguring to encode from texture."); | |
633 } | |
596 if (reconfigure_due_to_size) { | 634 if (reconfigure_due_to_size) { |
597 ALOGD << "Reconfigure encoder due to frame resolution change from " | 635 ALOGD << "Reconfigure encoder due to frame resolution change from " |
598 << width_ << " x " << height_ << " to " << frame.width() << " x " | 636 << width_ << " x " << height_ << " to " << frame.width() << " x " |
599 << frame.height(); | 637 << frame.height(); |
600 width_ = frame.width(); | 638 width_ = frame.width(); |
601 height_ = frame.height(); | 639 height_ = frame.height(); |
602 } | 640 } |
603 | 641 |
604 if (!reconfigure_due_to_size) | 642 if (!reconfigure_due_to_format && !reconfigure_due_to_size) |
605 return true; | 643 return true; |
606 | 644 |
607 ReleaseOnCodecThread(); | 645 ReleaseOnCodecThread(); |
608 | 646 |
609 return InitEncodeOnCodecThread(width_, height_, 0, 0) == | 647 return InitEncodeOnCodecThread(width_, height_, 0, 0 , is_texture_frame) == |
610 WEBRTC_VIDEO_CODEC_OK; | 648 WEBRTC_VIDEO_CODEC_OK; |
611 } | 649 } |
612 | 650 |
613 bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni, | 651 bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni, |
614 bool key_frame, const webrtc::VideoFrame& frame) { | 652 bool key_frame, const webrtc::VideoFrame& frame) { |
615 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 653 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
654 RTC_CHECK(!use_surface_); | |
616 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, | 655 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, |
617 j_dequeue_input_buffer_method_); | 656 j_dequeue_input_buffer_method_); |
618 CHECK_EXCEPTION(jni); | 657 CHECK_EXCEPTION(jni); |
619 if (j_input_buffer_index == -1) { | 658 if (j_input_buffer_index == -1) { |
620 // Video codec falls behind - no input buffer available. | 659 // Video codec falls behind - no input buffer available. |
621 ALOGD <<"Encoder drop frame - no input buffers available"; | 660 ALOGD <<"Encoder drop frame - no input buffers available"; |
622 frames_dropped_++; | 661 frames_dropped_++; |
623 // Report dropped frame to quality_scaler_. | 662 // Report dropped frame to quality_scaler_. |
624 OnDroppedFrame(); | 663 OnDroppedFrame(); |
625 return true; // TODO(fischman): see webrtc bug 2887. | 664 return true; // TODO(fischman): see webrtc bug 2887. |
(...skipping 21 matching lines...) Expand all Loading... | |
647 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | 686 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, |
648 j_encode_buffer_method_, | 687 j_encode_buffer_method_, |
649 key_frame, | 688 key_frame, |
650 j_input_buffer_index, | 689 j_input_buffer_index, |
651 yuv_size_, | 690 yuv_size_, |
652 current_timestamp_us_); | 691 current_timestamp_us_); |
653 CHECK_EXCEPTION(jni); | 692 CHECK_EXCEPTION(jni); |
654 return encode_status; | 693 return encode_status; |
655 } | 694 } |
656 | 695 |
696 bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni, | |
697 bool key_frame, const webrtc::VideoFrame& frame) { | |
698 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | |
699 RTC_CHECK(use_surface_); | |
700 NativeHandleImpl* handle = | |
AlexG
2015/10/14 23:48:27
How do you handle slow encoder cases here if encod
perkj_webrtc
2015/11/16 13:08:51
The same. Dropping happens before this function is
| |
701 static_cast<NativeHandleImpl*>(frame.native_handle()); | |
702 jfloatArray sampling_matrix = jni->NewFloatArray(16); | |
703 jni->SetFloatArrayRegion(sampling_matrix, 0, 16, handle->sampling_matrix); | |
704 | |
705 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | |
706 j_encode_texture_method_, | |
707 key_frame, | |
708 handle->oes_texture_id, | |
709 sampling_matrix, | |
710 current_timestamp_us_); | |
711 CHECK_EXCEPTION(jni); | |
712 return encode_status; | |
713 } | |
714 | |
657 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( | 715 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( |
658 webrtc::EncodedImageCallback* callback) { | 716 webrtc::EncodedImageCallback* callback) { |
659 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 717 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
660 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 718 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
661 ScopedLocalRefFrame local_ref_frame(jni); | 719 ScopedLocalRefFrame local_ref_frame(jni); |
662 callback_ = callback; | 720 callback_ = callback; |
663 return WEBRTC_VIDEO_CODEC_OK; | 721 return WEBRTC_VIDEO_CODEC_OK; |
664 } | 722 } |
665 | 723 |
666 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { | 724 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
941 | 999 |
942 void MediaCodecVideoEncoder::OnDroppedFrame() { | 1000 void MediaCodecVideoEncoder::OnDroppedFrame() { |
943 if (scale_) | 1001 if (scale_) |
944 quality_scaler_.ReportDroppedFrame(); | 1002 quality_scaler_.ReportDroppedFrame(); |
945 } | 1003 } |
946 | 1004 |
947 int MediaCodecVideoEncoder::GetTargetFramerate() { | 1005 int MediaCodecVideoEncoder::GetTargetFramerate() { |
948 return scale_ ? quality_scaler_.GetTargetFramerate() : -1; | 1006 return scale_ ? quality_scaler_.GetTargetFramerate() : -1; |
949 } | 1007 } |
950 | 1008 |
951 MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() { | 1009 MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() |
1010 : egl_context_ (nullptr) { | |
952 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 1011 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
953 ScopedLocalRefFrame local_ref_frame(jni); | 1012 ScopedLocalRefFrame local_ref_frame(jni); |
954 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder"); | 1013 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder"); |
955 supported_codecs_.clear(); | 1014 supported_codecs_.clear(); |
956 | 1015 |
957 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod( | 1016 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod( |
958 j_encoder_class, | 1017 j_encoder_class, |
959 GetStaticMethodID(jni, j_encoder_class, "isVp8HwSupported", "()Z")); | 1018 GetStaticMethodID(jni, j_encoder_class, "isVp8HwSupported", "()Z")); |
960 CHECK_EXCEPTION(jni); | 1019 CHECK_EXCEPTION(jni); |
961 if (is_vp8_hw_supported) { | 1020 if (is_vp8_hw_supported) { |
962 ALOGD << "VP8 HW Encoder supported."; | 1021 ALOGD << "VP8 HW Encoder supported."; |
963 supported_codecs_.push_back(VideoCodec(kVideoCodecVP8, "VP8", | 1022 supported_codecs_.push_back(VideoCodec(kVideoCodecVP8, "VP8", |
964 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); | 1023 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); |
965 } | 1024 } |
966 | 1025 |
967 bool is_h264_hw_supported = jni->CallStaticBooleanMethod( | 1026 bool is_h264_hw_supported = jni->CallStaticBooleanMethod( |
968 j_encoder_class, | 1027 j_encoder_class, |
969 GetStaticMethodID(jni, j_encoder_class, "isH264HwSupported", "()Z")); | 1028 GetStaticMethodID(jni, j_encoder_class, "isH264HwSupported", "()Z")); |
970 CHECK_EXCEPTION(jni); | 1029 CHECK_EXCEPTION(jni); |
971 if (is_h264_hw_supported) { | 1030 if (is_h264_hw_supported) { |
972 ALOGD << "H.264 HW Encoder supported."; | 1031 ALOGD << "H.264 HW Encoder supported."; |
973 supported_codecs_.push_back(VideoCodec(kVideoCodecH264, "H264", | 1032 supported_codecs_.push_back(VideoCodec(kVideoCodecH264, "H264", |
974 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); | 1033 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); |
975 } | 1034 } |
976 } | 1035 } |
977 | 1036 |
978 MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {} | 1037 MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {} |
979 | 1038 |
1039 void MediaCodecVideoEncoderFactory::SetEGLContext( | |
1040 JNIEnv* jni, jobject render_egl_context) { | |
1041 ALOGD << "MediaCodecVideoEncoderFactory::SetEGLContext"; | |
1042 if (egl_context_) { | |
1043 jni->DeleteGlobalRef(egl_context_); | |
1044 egl_context_ = NULL; | |
1045 } | |
1046 if (!IsNull(jni, render_egl_context)) { | |
1047 egl_context_ = jni->NewGlobalRef(render_egl_context); | |
1048 if (CheckException(jni)) { | |
1049 ALOGE << "error calling NewGlobalRef for EGL Context."; | |
1050 egl_context_ = NULL; | |
1051 } else { | |
1052 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext"); | |
1053 if (!jni->IsInstanceOf(egl_context_, j_egl_context_class)) { | |
1054 ALOGE << "Wrong EGL Context."; | |
1055 jni->DeleteGlobalRef(egl_context_); | |
1056 egl_context_ = NULL; | |
1057 } | |
1058 } | |
1059 } | |
1060 if (egl_context_ == NULL) { | |
1061 ALOGW << "NULL VideoDecoder EGL context - HW surface encoding is disabled."; | |
1062 } | |
1063 } | |
1064 | |
980 webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder( | 1065 webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder( |
981 VideoCodecType type) { | 1066 VideoCodecType type) { |
982 if (supported_codecs_.empty()) { | 1067 if (supported_codecs_.empty()) { |
983 return NULL; | 1068 return NULL; |
984 } | 1069 } |
985 for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin(); | 1070 for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin(); |
986 it != supported_codecs_.end(); ++it) { | 1071 it != supported_codecs_.end(); ++it) { |
987 if (it->type == type) { | 1072 if (it->type == type) { |
988 ALOGD << "Create HW video encoder for type " << (int)type << | 1073 ALOGD << "Create HW video encoder for type " << (int)type << |
989 " (" << it->name << ")."; | 1074 " (" << it->name << ")."; |
990 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type); | 1075 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type, |
1076 egl_context_); | |
991 } | 1077 } |
992 } | 1078 } |
993 return NULL; | 1079 return NULL; |
994 } | 1080 } |
995 | 1081 |
996 const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>& | 1082 const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>& |
997 MediaCodecVideoEncoderFactory::codecs() const { | 1083 MediaCodecVideoEncoderFactory::codecs() const { |
998 return supported_codecs_; | 1084 return supported_codecs_; |
999 } | 1085 } |
1000 | 1086 |
1001 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( | 1087 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( |
1002 webrtc::VideoEncoder* encoder) { | 1088 webrtc::VideoEncoder* encoder) { |
1003 ALOGD << "Destroy video encoder."; | 1089 ALOGD << "Destroy video encoder."; |
1004 delete encoder; | 1090 delete encoder; |
1005 } | 1091 } |
1006 | 1092 |
1007 } // namespace webrtc_jni | 1093 } // namespace webrtc_jni |
1008 | 1094 |
OLD | NEW |