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/include/field_trial.h" | 42 #include "webrtc/system_wrappers/include/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(const webrtc::VideoFrame& input_image, | 93 int32_t Encode(const webrtc::VideoFrame& input_image, |
92 const webrtc::CodecSpecificInfo* /* codec_specific_info */, | 94 const webrtc::CodecSpecificInfo* /* codec_specific_info */, |
93 const std::vector<webrtc::FrameType>* frame_types) override; | 95 const std::vector<webrtc::FrameType>* frame_types) override; |
94 int32_t RegisterEncodeCompleteCallback( | 96 int32_t RegisterEncodeCompleteCallback( |
95 webrtc::EncodedImageCallback* callback) override; | 97 webrtc::EncodedImageCallback* callback) override; |
96 int32_t Release() override; | 98 int32_t Release() override; |
97 int32_t SetChannelParameters(uint32_t /* packet_loss */, | 99 int32_t SetChannelParameters(uint32_t /* packet_loss */, |
98 int64_t /* rtt */) override; | 100 int64_t /* rtt */) override; |
99 int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) override; | 101 int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) override; |
100 | 102 |
101 // rtc::MessageHandler implementation. | 103 // rtc::MessageHandler implementation. |
102 void OnMessage(rtc::Message* msg) override; | 104 void OnMessage(rtc::Message* msg) override; |
103 | 105 |
104 void OnDroppedFrame() override; | 106 void OnDroppedFrame() override; |
105 | 107 |
106 int GetTargetFramerate() override; | 108 int GetTargetFramerate() override; |
107 | 109 |
110 bool SupportsNativeHandle() const override { return true; } | |
111 | |
108 private: | 112 private: |
109 // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and | 113 // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and |
110 // InitEncodeOnCodecThread() in an attempt to restore the codec to an | 114 // InitEncodeOnCodecThread() in an attempt to restore the codec to an |
111 // operable state. Necessary after all manner of OMX-layer errors. | 115 // operable state. Necessary after all manner of OMX-layer errors. |
112 bool ResetCodecOnCodecThread(); | 116 bool ResetCodecOnCodecThread(); |
113 | 117 |
114 // Implementation of webrtc::VideoEncoder methods above, all running on the | 118 // Implementation of webrtc::VideoEncoder methods above, all running on the |
115 // codec thread exclusively. | 119 // codec thread exclusively. |
116 // | 120 // |
117 // If width==0 then this is assumed to be a re-initialization and the | 121 // If width==0 then this is assumed to be a re-initialization and the |
118 // previously-current values are reused instead of the passed parameters | 122 // previously-current values are reused instead of the passed parameters |
119 // (makes it easier to reason about thread-safety). | 123 // (makes it easier to reason about thread-safety). |
120 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps); | 124 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps, |
121 // Reconfigure to match |frame| in width, height. Returns false if | 125 bool use_surface); |
122 // reconfiguring fails. | 126 // Reconfigure to match |frame| in width, height. Also reconfigures the |
127 // encoder if |frame| is a texture/byte buffer and the encoder is initialized | |
128 // for byte buffer/texture. Returns false if reconfiguring fails. | |
123 bool MaybeReconfigureEncoderOnCodecThread(const webrtc::VideoFrame& frame); | 129 bool MaybeReconfigureEncoderOnCodecThread(const webrtc::VideoFrame& frame); |
124 int32_t EncodeOnCodecThread( | 130 int32_t EncodeOnCodecThread( |
125 const webrtc::VideoFrame& input_image, | 131 const webrtc::VideoFrame& input_image, |
126 const std::vector<webrtc::FrameType>* frame_types); | 132 const std::vector<webrtc::FrameType>* frame_types); |
127 bool EncodeByteBufferOnCodecThread(JNIEnv* jni, | 133 bool EncodeByteBufferOnCodecThread(JNIEnv* jni, |
128 bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index); | 134 bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index); |
135 bool EncodeTextureOnCodecThread(JNIEnv* jni, | |
136 bool key_frame, const webrtc::VideoFrame& frame); | |
129 | 137 |
130 int32_t RegisterEncodeCompleteCallbackOnCodecThread( | 138 int32_t RegisterEncodeCompleteCallbackOnCodecThread( |
131 webrtc::EncodedImageCallback* callback); | 139 webrtc::EncodedImageCallback* callback); |
132 int32_t ReleaseOnCodecThread(); | 140 int32_t ReleaseOnCodecThread(); |
133 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate); | 141 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate); |
134 | 142 |
135 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members. | 143 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members. |
136 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info); | 144 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info); |
137 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info); | 145 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info); |
138 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info); | 146 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info); |
(...skipping 17 matching lines...) Expand all Loading... | |
156 // State that is constant for the lifetime of this object once the ctor | 164 // State that is constant for the lifetime of this object once the ctor |
157 // returns. | 165 // returns. |
158 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. | 166 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. |
159 rtc::ThreadChecker codec_thread_checker_; | 167 rtc::ThreadChecker codec_thread_checker_; |
160 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_; | 168 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_; |
161 ScopedGlobalRef<jobject> j_media_codec_video_encoder_; | 169 ScopedGlobalRef<jobject> j_media_codec_video_encoder_; |
162 jmethodID j_init_encode_method_; | 170 jmethodID j_init_encode_method_; |
163 jmethodID j_get_input_buffers_method_; | 171 jmethodID j_get_input_buffers_method_; |
164 jmethodID j_dequeue_input_buffer_method_; | 172 jmethodID j_dequeue_input_buffer_method_; |
165 jmethodID j_encode_buffer_method_; | 173 jmethodID j_encode_buffer_method_; |
174 jmethodID j_encode_texture_method_; | |
166 jmethodID j_release_method_; | 175 jmethodID j_release_method_; |
167 jmethodID j_set_rates_method_; | 176 jmethodID j_set_rates_method_; |
168 jmethodID j_dequeue_output_buffer_method_; | 177 jmethodID j_dequeue_output_buffer_method_; |
169 jmethodID j_release_output_buffer_method_; | 178 jmethodID j_release_output_buffer_method_; |
170 jfieldID j_color_format_field_; | 179 jfieldID j_color_format_field_; |
171 jfieldID j_info_index_field_; | 180 jfieldID j_info_index_field_; |
172 jfieldID j_info_buffer_field_; | 181 jfieldID j_info_buffer_field_; |
173 jfieldID j_info_is_key_frame_field_; | 182 jfieldID j_info_is_key_frame_field_; |
174 jfieldID j_info_presentation_timestamp_us_field_; | 183 jfieldID j_info_presentation_timestamp_us_field_; |
175 | 184 |
176 // State that is valid only between InitEncode() and the next Release(). | 185 // State that is valid only between InitEncode() and the next Release(). |
177 // Touched only on codec_thread_ so no explicit synchronization necessary. | 186 // Touched only on codec_thread_ so no explicit synchronization necessary. |
178 int width_; // Frame width in pixels. | 187 int width_; // Frame width in pixels. |
179 int height_; // Frame height in pixels. | 188 int height_; // Frame height in pixels. |
180 bool inited_; | 189 bool inited_; |
190 bool use_surface_; | |
181 uint16_t picture_id_; | 191 uint16_t picture_id_; |
182 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format. | 192 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format. |
183 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps. | 193 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps. |
184 int last_set_fps_; // Last-requested frame rate. | 194 int last_set_fps_; // Last-requested frame rate. |
185 int64_t current_timestamp_us_; // Current frame timestamps in us. | 195 int64_t current_timestamp_us_; // Current frame timestamps in us. |
186 int frames_received_; // Number of frames received by encoder. | 196 int frames_received_; // Number of frames received by encoder. |
187 int frames_encoded_; // Number of frames encoded by encoder. | 197 int frames_encoded_; // Number of frames encoded by encoder. |
188 int frames_dropped_; // Number of frames dropped by encoder. | 198 int frames_dropped_; // Number of frames dropped by encoder. |
189 int frames_in_queue_; // Number of frames in encoder queue. | 199 int frames_in_queue_; // Number of frames in encoder queue. |
190 int64_t start_time_ms_; // Start time for statistics. | 200 int64_t start_time_ms_; // Start time for statistics. |
(...skipping 15 matching lines...) Expand all Loading... | |
206 // and the next Encode() call being ignored. | 216 // and the next Encode() call being ignored. |
207 bool drop_next_input_frame_; | 217 bool drop_next_input_frame_; |
208 // Global references; must be deleted in Release(). | 218 // Global references; must be deleted in Release(). |
209 std::vector<jobject> input_buffers_; | 219 std::vector<jobject> input_buffers_; |
210 webrtc::QualityScaler quality_scaler_; | 220 webrtc::QualityScaler quality_scaler_; |
211 // Dynamic resolution change, off by default. | 221 // Dynamic resolution change, off by default. |
212 bool scale_; | 222 bool scale_; |
213 | 223 |
214 // H264 bitstream parser, used to extract QP from encoded bitstreams. | 224 // H264 bitstream parser, used to extract QP from encoded bitstreams. |
215 webrtc::H264BitstreamParser h264_bitstream_parser_; | 225 webrtc::H264BitstreamParser h264_bitstream_parser_; |
226 | |
227 // EGL context - owned by factory, should not be allocated/destroyed | |
228 // by MediaCodecVideoEncoder. | |
229 jobject egl_context_; | |
216 }; | 230 }; |
217 | 231 |
218 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { | 232 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { |
219 // Call Release() to ensure no more callbacks to us after we are deleted. | 233 // Call Release() to ensure no more callbacks to us after we are deleted. |
220 Release(); | 234 Release(); |
221 } | 235 } |
222 | 236 |
223 MediaCodecVideoEncoder::MediaCodecVideoEncoder( | 237 MediaCodecVideoEncoder::MediaCodecVideoEncoder( |
224 JNIEnv* jni, VideoCodecType codecType) : | 238 JNIEnv* jni, VideoCodecType codecType, jobject egl_context) : |
225 codecType_(codecType), | 239 codecType_(codecType), |
226 callback_(NULL), | 240 callback_(NULL), |
227 inited_(false), | 241 inited_(false), |
242 use_surface_(false), | |
228 picture_id_(0), | 243 picture_id_(0), |
229 codec_thread_(new Thread()), | 244 codec_thread_(new Thread()), |
230 j_media_codec_video_encoder_class_( | 245 j_media_codec_video_encoder_class_( |
231 jni, | 246 jni, |
232 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")), | 247 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")), |
233 j_media_codec_video_encoder_( | 248 j_media_codec_video_encoder_( |
234 jni, | 249 jni, |
235 jni->NewObject(*j_media_codec_video_encoder_class_, | 250 jni->NewObject(*j_media_codec_video_encoder_class_, |
236 GetMethodID(jni, | 251 GetMethodID(jni, |
237 *j_media_codec_video_encoder_class_, | 252 *j_media_codec_video_encoder_class_, |
238 "<init>", | 253 "<init>", |
239 "()V"))) { | 254 "()V"))), |
255 egl_context_(egl_context) { | |
240 ScopedLocalRefFrame local_ref_frame(jni); | 256 ScopedLocalRefFrame local_ref_frame(jni); |
241 // It would be nice to avoid spinning up a new thread per MediaCodec, and | 257 // It would be nice to avoid spinning up a new thread per MediaCodec, and |
242 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug | 258 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug |
243 // 2732 means that deadlocks abound. This class synchronously trampolines | 259 // 2732 means that deadlocks abound. This class synchronously trampolines |
244 // to |codec_thread_|, so if anything else can be coming to _us_ from | 260 // to |codec_thread_|, so if anything else can be coming to _us_ from |
245 // |codec_thread_|, or from any thread holding the |_sendCritSect| described | 261 // |codec_thread_|, or from any thread holding the |_sendCritSect| described |
246 // in the bug, we have a problem. For now work around that with a dedicated | 262 // in the bug, we have a problem. For now work around that with a dedicated |
247 // thread. | 263 // thread. |
248 codec_thread_->SetName("MediaCodecVideoEncoder", NULL); | 264 codec_thread_->SetName("MediaCodecVideoEncoder", NULL); |
249 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; | 265 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; |
250 codec_thread_checker_.DetachFromThread(); | 266 codec_thread_checker_.DetachFromThread(); |
251 jclass j_output_buffer_info_class = | 267 jclass j_output_buffer_info_class = |
252 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo"); | 268 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo"); |
253 j_init_encode_method_ = GetMethodID( | 269 j_init_encode_method_ = GetMethodID( |
254 jni, | 270 jni, |
255 *j_media_codec_video_encoder_class_, | 271 *j_media_codec_video_encoder_class_, |
256 "initEncode", | 272 "initEncode", |
257 "(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;IIII)Z"); | 273 "(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;" |
274 "IIIILjavax/microedition/khronos/egl/EGLContext;)Z"); | |
258 j_get_input_buffers_method_ = GetMethodID( | 275 j_get_input_buffers_method_ = GetMethodID( |
259 jni, | 276 jni, |
260 *j_media_codec_video_encoder_class_, | 277 *j_media_codec_video_encoder_class_, |
261 "getInputBuffers", | 278 "getInputBuffers", |
262 "()[Ljava/nio/ByteBuffer;"); | 279 "()[Ljava/nio/ByteBuffer;"); |
263 j_dequeue_input_buffer_method_ = GetMethodID( | 280 j_dequeue_input_buffer_method_ = GetMethodID( |
264 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I"); | 281 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I"); |
265 j_encode_buffer_method_ = GetMethodID( | 282 j_encode_buffer_method_ = GetMethodID( |
266 jni, *j_media_codec_video_encoder_class_, "encodeBuffer", "(ZIIJ)Z"); | 283 jni, *j_media_codec_video_encoder_class_, "encodeBuffer", "(ZIIJ)Z"); |
284 j_encode_texture_method_ = GetMethodID( | |
285 jni, *j_media_codec_video_encoder_class_, "encodeTexture", | |
286 "(ZI[FJ)Z"); | |
267 j_release_method_ = | 287 j_release_method_ = |
268 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V"); | 288 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V"); |
269 j_set_rates_method_ = GetMethodID( | 289 j_set_rates_method_ = GetMethodID( |
270 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z"); | 290 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z"); |
271 j_dequeue_output_buffer_method_ = GetMethodID( | 291 j_dequeue_output_buffer_method_ = GetMethodID( |
272 jni, | 292 jni, |
273 *j_media_codec_video_encoder_class_, | 293 *j_media_codec_video_encoder_class_, |
274 "dequeueOutputBuffer", | 294 "dequeueOutputBuffer", |
275 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;"); | 295 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;"); |
276 j_release_output_buffer_method_ = GetMethodID( | 296 j_release_output_buffer_method_ = GetMethodID( |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
336 } | 356 } |
337 quality_scaler_.SetMinResolution(kMinWidth, kMinHeight); | 357 quality_scaler_.SetMinResolution(kMinWidth, kMinHeight); |
338 quality_scaler_.ReportFramerate(codec_settings->maxFramerate); | 358 quality_scaler_.ReportFramerate(codec_settings->maxFramerate); |
339 } | 359 } |
340 return codec_thread_->Invoke<int32_t>( | 360 return codec_thread_->Invoke<int32_t>( |
341 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread, | 361 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread, |
342 this, | 362 this, |
343 codec_settings->width, | 363 codec_settings->width, |
344 codec_settings->height, | 364 codec_settings->height, |
345 codec_settings->startBitrate, | 365 codec_settings->startBitrate, |
346 codec_settings->maxFramerate)); | 366 codec_settings->maxFramerate, |
367 false /*use_surface*/)); | |
magjed_webrtc
2015/11/18 13:12:52
/* use_surface */
perkj_webrtc
2015/11/18 14:51:21
Done.
| |
347 } | 368 } |
348 | 369 |
349 int32_t MediaCodecVideoEncoder::Encode( | 370 int32_t MediaCodecVideoEncoder::Encode( |
350 const webrtc::VideoFrame& frame, | 371 const webrtc::VideoFrame& frame, |
351 const webrtc::CodecSpecificInfo* /* codec_specific_info */, | 372 const webrtc::CodecSpecificInfo* /* codec_specific_info */, |
352 const std::vector<webrtc::FrameType>* frame_types) { | 373 const std::vector<webrtc::FrameType>* frame_types) { |
353 return codec_thread_->Invoke<int32_t>(Bind( | 374 return codec_thread_->Invoke<int32_t>(Bind( |
354 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types)); | 375 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types)); |
355 } | 376 } |
356 | 377 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
402 // unclear how to signal such a failure to the app, so instead we stay silent | 423 // unclear how to signal such a failure to the app, so instead we stay silent |
403 // about it and let the next app-called API method reveal the borkedness. | 424 // about it and let the next app-called API method reveal the borkedness. |
404 DeliverPendingOutputs(jni); | 425 DeliverPendingOutputs(jni); |
405 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | 426 codec_thread_->PostDelayed(kMediaCodecPollMs, this); |
406 } | 427 } |
407 | 428 |
408 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { | 429 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { |
409 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 430 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
410 ALOGE << "ResetOnCodecThread"; | 431 ALOGE << "ResetOnCodecThread"; |
411 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || | 432 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || |
412 InitEncodeOnCodecThread(width_, height_, 0, 0) | 433 InitEncodeOnCodecThread(width_, height_, 0, 0, false) != |
413 != WEBRTC_VIDEO_CODEC_OK) { | 434 WEBRTC_VIDEO_CODEC_OK) { |
414 // TODO(fischman): wouldn't it be nice if there was a way to gracefully | 435 // TODO(fischman): wouldn't it be nice if there was a way to gracefully |
415 // degrade to a SW encoder at this point? There isn't one AFAICT :( | 436 // degrade to a SW encoder at this point? There isn't one AFAICT :( |
416 // https://code.google.com/p/webrtc/issues/detail?id=2920 | 437 // https://code.google.com/p/webrtc/issues/detail?id=2920 |
417 return false; | 438 return false; |
418 } | 439 } |
419 return true; | 440 return true; |
420 } | 441 } |
421 | 442 |
422 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( | 443 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( |
423 int width, int height, int kbps, int fps) { | 444 int width, int height, int kbps, int fps, bool use_surface) { |
424 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 445 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
446 RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set."; | |
425 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 447 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
426 ScopedLocalRefFrame local_ref_frame(jni); | 448 ScopedLocalRefFrame local_ref_frame(jni); |
427 | 449 |
428 ALOGD << "InitEncodeOnCodecThread Type: " << (int)codecType_ << ", " << | 450 ALOGD << "InitEncodeOnCodecThread Type: " << (int)codecType_ << ", " << |
429 width << " x " << height << ". Bitrate: " << kbps << | 451 width << " x " << height << ". Bitrate: " << kbps << |
430 " kbps. Fps: " << fps; | 452 " kbps. Fps: " << fps; |
431 if (kbps == 0) { | 453 if (kbps == 0) { |
432 kbps = last_set_bitrate_kbps_; | 454 kbps = last_set_bitrate_kbps_; |
433 } | 455 } |
434 if (fps == 0) { | 456 if (fps == 0) { |
(...skipping 22 matching lines...) Expand all Loading... | |
457 render_times_ms_.clear(); | 479 render_times_ms_.clear(); |
458 frame_rtc_times_ms_.clear(); | 480 frame_rtc_times_ms_.clear(); |
459 drop_next_input_frame_ = false; | 481 drop_next_input_frame_ = false; |
460 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; | 482 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; |
461 | 483 |
462 // We enforce no extra stride/padding in the format creation step. | 484 // We enforce no extra stride/padding in the format creation step. |
463 jobject j_video_codec_enum = JavaEnumFromIndex( | 485 jobject j_video_codec_enum = JavaEnumFromIndex( |
464 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); | 486 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); |
465 const bool encode_status = jni->CallBooleanMethod( | 487 const bool encode_status = jni->CallBooleanMethod( |
466 *j_media_codec_video_encoder_, j_init_encode_method_, | 488 *j_media_codec_video_encoder_, j_init_encode_method_, |
467 j_video_codec_enum, width, height, kbps, fps); | 489 j_video_codec_enum, width, height, kbps, fps, |
490 (use_surface ? egl_context_ : nullptr)); | |
468 if (!encode_status) { | 491 if (!encode_status) { |
469 ALOGE << "Failed to configure encoder."; | 492 ALOGE << "Failed to configure encoder."; |
470 return WEBRTC_VIDEO_CODEC_ERROR; | 493 return WEBRTC_VIDEO_CODEC_ERROR; |
471 } | 494 } |
472 CHECK_EXCEPTION(jni); | 495 CHECK_EXCEPTION(jni); |
473 | 496 |
474 jobjectArray input_buffers = reinterpret_cast<jobjectArray>( | 497 if (use_surface) { |
475 jni->CallObjectMethod(*j_media_codec_video_encoder_, | 498 scale_ = false; // TODO(perkj): Implement scaling when using textures. |
476 j_get_input_buffers_method_)); | 499 use_surface_ = true; |
magjed_webrtc
2015/11/18 13:12:52
This looks strange, can you only enable surface en
perkj_webrtc
2015/11/18 14:51:21
that is strange - but works. I reset in Reset... A
| |
477 CHECK_EXCEPTION(jni); | 500 } else { |
478 if (IsNull(jni, input_buffers)) { | 501 jobjectArray input_buffers = reinterpret_cast<jobjectArray>( |
479 return WEBRTC_VIDEO_CODEC_ERROR; | 502 jni->CallObjectMethod(*j_media_codec_video_encoder_, |
503 j_get_input_buffers_method_)); | |
504 CHECK_EXCEPTION(jni); | |
505 if (IsNull(jni, input_buffers)) { | |
506 return WEBRTC_VIDEO_CODEC_ERROR; | |
507 } | |
508 | |
509 switch (GetIntField(jni, *j_media_codec_video_encoder_, | |
510 j_color_format_field_)) { | |
511 case COLOR_FormatYUV420Planar: | |
512 encoder_fourcc_ = libyuv::FOURCC_YU12; | |
513 break; | |
514 case COLOR_FormatYUV420SemiPlanar: | |
515 case COLOR_QCOM_FormatYUV420SemiPlanar: | |
516 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: | |
517 encoder_fourcc_ = libyuv::FOURCC_NV12; | |
518 break; | |
519 default: | |
520 LOG(LS_ERROR) << "Wrong color format."; | |
521 return WEBRTC_VIDEO_CODEC_ERROR; | |
522 } | |
523 size_t num_input_buffers = jni->GetArrayLength(input_buffers); | |
524 RTC_CHECK(input_buffers_.empty()) | |
525 << "Unexpected double InitEncode without Release"; | |
526 input_buffers_.resize(num_input_buffers); | |
527 for (size_t i = 0; i < num_input_buffers; ++i) { | |
528 input_buffers_[i] = | |
529 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); | |
530 int64_t yuv_buffer_capacity = | |
531 jni->GetDirectBufferCapacity(input_buffers_[i]); | |
532 CHECK_EXCEPTION(jni); | |
533 RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; | |
534 } | |
480 } | 535 } |
481 | 536 |
482 switch (GetIntField(jni, *j_media_codec_video_encoder_, | |
483 j_color_format_field_)) { | |
484 case COLOR_FormatYUV420Planar: | |
485 encoder_fourcc_ = libyuv::FOURCC_YU12; | |
486 break; | |
487 case COLOR_FormatYUV420SemiPlanar: | |
488 case COLOR_QCOM_FormatYUV420SemiPlanar: | |
489 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: | |
490 encoder_fourcc_ = libyuv::FOURCC_NV12; | |
491 break; | |
492 default: | |
493 LOG(LS_ERROR) << "Wrong color format."; | |
494 return WEBRTC_VIDEO_CODEC_ERROR; | |
495 } | |
496 size_t num_input_buffers = jni->GetArrayLength(input_buffers); | |
497 RTC_CHECK(input_buffers_.empty()) | |
498 << "Unexpected double InitEncode without Release"; | |
499 input_buffers_.resize(num_input_buffers); | |
500 for (size_t i = 0; i < num_input_buffers; ++i) { | |
501 input_buffers_[i] = | |
502 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); | |
503 int64_t yuv_buffer_capacity = | |
504 jni->GetDirectBufferCapacity(input_buffers_[i]); | |
505 CHECK_EXCEPTION(jni); | |
506 RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; | |
507 } | |
508 CHECK_EXCEPTION(jni); | |
509 | |
510 | |
511 inited_ = true; | 537 inited_ = true; |
512 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | 538 codec_thread_->PostDelayed(kMediaCodecPollMs, this); |
513 return WEBRTC_VIDEO_CODEC_OK; | 539 return WEBRTC_VIDEO_CODEC_OK; |
514 } | 540 } |
515 | 541 |
516 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( | 542 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
517 const webrtc::VideoFrame& frame, | 543 const webrtc::VideoFrame& frame, |
518 const std::vector<webrtc::FrameType>* frame_types) { | 544 const std::vector<webrtc::FrameType>* frame_types) { |
519 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 545 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
520 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 546 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
557 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) { | 583 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) { |
558 ALOGD << "Drop frame - encoder is behind by " << encoder_latency_ms << | 584 ALOGD << "Drop frame - encoder is behind by " << encoder_latency_ms << |
559 " ms. Q size: " << frames_in_queue_; | 585 " ms. Q size: " << frames_in_queue_; |
560 frames_dropped_++; | 586 frames_dropped_++; |
561 // Report dropped frame to quality_scaler_. | 587 // Report dropped frame to quality_scaler_. |
562 OnDroppedFrame(); | 588 OnDroppedFrame(); |
563 return WEBRTC_VIDEO_CODEC_OK; | 589 return WEBRTC_VIDEO_CODEC_OK; |
564 } | 590 } |
565 } | 591 } |
566 | 592 |
567 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, | 593 const bool key_frame = frame_types->front() != webrtc::kVideoFrameDelta; |
568 j_dequeue_input_buffer_method_); | 594 bool encode_status = true; |
569 CHECK_EXCEPTION(jni); | 595 if (!input_frame.native_handle()) { |
570 if (j_input_buffer_index == -1) { | 596 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, |
571 // Video codec falls behind - no input buffer available. | 597 j_dequeue_input_buffer_method_); |
572 ALOGW << "Encoder drop frame - no input buffers available"; | 598 CHECK_EXCEPTION(jni); |
573 frames_dropped_++; | 599 if (j_input_buffer_index == -1) { |
574 // Report dropped frame to quality_scaler_. | 600 // Video codec falls behind - no input buffer available. |
575 OnDroppedFrame(); | 601 ALOGW << "Encoder drop frame - no input buffers available"; |
576 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887. | 602 frames_dropped_++; |
603 // Report dropped frame to quality_scaler_. | |
604 OnDroppedFrame(); | |
605 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887. | |
606 } | |
607 if (j_input_buffer_index == -2) { | |
608 ResetCodecOnCodecThread(); | |
609 return WEBRTC_VIDEO_CODEC_ERROR; | |
610 } | |
611 encode_status = EncodeByteBufferOnCodecThread(jni, key_frame, input_frame, | |
612 j_input_buffer_index); | |
613 } else { | |
614 encode_status = EncodeTextureOnCodecThread(jni, key_frame, input_frame); | |
577 } | 615 } |
578 if (j_input_buffer_index == -2) { | 616 |
617 if (!encode_status) { | |
618 ALOGE << "Failed encode frame with timestamp: " << input_frame.timestamp(); | |
579 ResetCodecOnCodecThread(); | 619 ResetCodecOnCodecThread(); |
580 return WEBRTC_VIDEO_CODEC_ERROR; | 620 return WEBRTC_VIDEO_CODEC_ERROR; |
581 } | 621 } |
582 | 622 |
583 last_input_timestamp_ms_ = | 623 last_input_timestamp_ms_ = |
584 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; | 624 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; |
585 frames_in_queue_++; | 625 frames_in_queue_++; |
586 | 626 |
587 // Save input image timestamps for later output | 627 // Save input image timestamps for later output |
588 timestamps_.push_back(input_frame.timestamp()); | 628 timestamps_.push_back(input_frame.timestamp()); |
589 render_times_ms_.push_back(input_frame.render_time_ms()); | 629 render_times_ms_.push_back(input_frame.render_time_ms()); |
590 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); | 630 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); |
591 | |
592 const bool key_frame = frame_types->front() != webrtc::kVideoFrameDelta; | |
593 const bool encode_status = | |
594 EncodeByteBufferOnCodecThread(jni, key_frame, input_frame, | |
595 j_input_buffer_index); | |
596 | |
597 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; | 631 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; |
598 | 632 |
599 if (!encode_status || !DeliverPendingOutputs(jni)) { | 633 if (!DeliverPendingOutputs(jni)) { |
600 ALOGE << "Failed deliver pending outputs."; | 634 ALOGE << "Failed deliver pending outputs."; |
601 ResetCodecOnCodecThread(); | 635 ResetCodecOnCodecThread(); |
602 return WEBRTC_VIDEO_CODEC_ERROR; | 636 return WEBRTC_VIDEO_CODEC_ERROR; |
603 } | 637 } |
604 return WEBRTC_VIDEO_CODEC_OK; | 638 return WEBRTC_VIDEO_CODEC_OK; |
605 } | 639 } |
606 | 640 |
607 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( | 641 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( |
608 const webrtc::VideoFrame& frame) { | 642 const webrtc::VideoFrame& frame) { |
609 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 643 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
610 | 644 |
611 const bool reconfigure_due_to_size = | 645 const bool is_texture_frame = frame.native_handle() != nullptr; |
646 const bool reconfigure_due_to_format = is_texture_frame != use_surface_; | |
647 bool reconfigure_due_to_size = | |
magjed_webrtc
2015/11/18 13:12:52
Why did you make |reconfigure_due_to_size| mutable
perkj_webrtc
2015/11/18 14:51:21
....
| |
612 frame.width() != width_ || frame.height() != height_; | 648 frame.width() != width_ || frame.height() != height_; |
613 | 649 |
650 if (reconfigure_due_to_format) { | |
651 ALOGD << "Reconfigure encoder due to format change. " | |
652 << (use_surface_ ? | |
653 "Reconfiguring to encode from byte buffer." : | |
654 "Reconfiguring to encode from texture."); | |
655 } | |
614 if (reconfigure_due_to_size) { | 656 if (reconfigure_due_to_size) { |
615 ALOGD << "Reconfigure encoder due to frame resolution change from " | 657 ALOGD << "Reconfigure encoder due to frame resolution change from " |
616 << width_ << " x " << height_ << " to " << frame.width() << " x " | 658 << width_ << " x " << height_ << " to " << frame.width() << " x " |
617 << frame.height(); | 659 << frame.height(); |
618 width_ = frame.width(); | 660 width_ = frame.width(); |
619 height_ = frame.height(); | 661 height_ = frame.height(); |
620 } | 662 } |
621 | 663 |
622 if (!reconfigure_due_to_size) | 664 if (!reconfigure_due_to_format && !reconfigure_due_to_size) |
623 return true; | 665 return true; |
624 | 666 |
625 ReleaseOnCodecThread(); | 667 ReleaseOnCodecThread(); |
626 | 668 |
627 return InitEncodeOnCodecThread(width_, height_, 0, 0) == | 669 return InitEncodeOnCodecThread(width_, height_, 0, 0 , is_texture_frame) == |
628 WEBRTC_VIDEO_CODEC_OK; | 670 WEBRTC_VIDEO_CODEC_OK; |
629 } | 671 } |
630 | 672 |
631 bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni, | 673 bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni, |
632 bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index) { | 674 bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index) { |
633 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 675 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
676 RTC_CHECK(!use_surface_); | |
634 | 677 |
635 ALOGV("Encoder frame in # %d. TS: %lld. Q: %d", | 678 ALOGV("Encoder frame in # %d. TS: %lld. Q: %d", |
636 frames_received_ - 1, current_timestamp_us_ / 1000, frames_in_queue_); | 679 frames_received_ - 1, current_timestamp_us_ / 1000, frames_in_queue_); |
637 | 680 |
638 jobject j_input_buffer = input_buffers_[input_buffer_index]; | 681 jobject j_input_buffer = input_buffers_[input_buffer_index]; |
639 uint8_t* yuv_buffer = | 682 uint8_t* yuv_buffer = |
640 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); | 683 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); |
641 CHECK_EXCEPTION(jni); | 684 CHECK_EXCEPTION(jni); |
642 RTC_CHECK(yuv_buffer) << "Indirect buffer??"; | 685 RTC_CHECK(yuv_buffer) << "Indirect buffer??"; |
643 RTC_CHECK(!libyuv::ConvertFromI420( | 686 RTC_CHECK(!libyuv::ConvertFromI420( |
644 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane), | 687 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane), |
645 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane), | 688 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane), |
646 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane), | 689 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane), |
647 yuv_buffer, width_, width_, height_, encoder_fourcc_)) | 690 yuv_buffer, width_, width_, height_, encoder_fourcc_)) |
648 << "ConvertFromI420 failed"; | 691 << "ConvertFromI420 failed"; |
649 | 692 |
650 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | 693 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, |
651 j_encode_buffer_method_, | 694 j_encode_buffer_method_, |
652 key_frame, | 695 key_frame, |
653 input_buffer_index, | 696 input_buffer_index, |
654 yuv_size_, | 697 yuv_size_, |
655 current_timestamp_us_); | 698 current_timestamp_us_); |
656 CHECK_EXCEPTION(jni); | 699 CHECK_EXCEPTION(jni); |
657 return encode_status; | 700 return encode_status; |
658 } | 701 } |
659 | 702 |
703 bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni, | |
704 bool key_frame, const webrtc::VideoFrame& frame) { | |
705 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | |
706 RTC_CHECK(use_surface_); | |
707 NativeHandleImpl* handle = | |
708 static_cast<NativeHandleImpl*>(frame.native_handle()); | |
709 jfloatArray sampling_matrix = jni->NewFloatArray(16); | |
710 jni->SetFloatArrayRegion(sampling_matrix, 0, 16, handle->sampling_matrix); | |
711 | |
712 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | |
713 j_encode_texture_method_, | |
714 key_frame, | |
715 handle->oes_texture_id, | |
716 sampling_matrix, | |
717 current_timestamp_us_); | |
718 CHECK_EXCEPTION(jni); | |
719 return encode_status; | |
720 } | |
721 | |
660 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( | 722 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( |
661 webrtc::EncodedImageCallback* callback) { | 723 webrtc::EncodedImageCallback* callback) { |
662 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 724 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
663 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 725 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
664 ScopedLocalRefFrame local_ref_frame(jni); | 726 ScopedLocalRefFrame local_ref_frame(jni); |
665 callback_ = callback; | 727 callback_ = callback; |
666 return WEBRTC_VIDEO_CODEC_OK; | 728 return WEBRTC_VIDEO_CODEC_OK; |
667 } | 729 } |
668 | 730 |
669 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { | 731 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { |
670 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 732 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
671 if (!inited_) { | 733 if (!inited_) { |
672 return WEBRTC_VIDEO_CODEC_OK; | 734 return WEBRTC_VIDEO_CODEC_OK; |
673 } | 735 } |
674 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 736 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
675 ALOGD << "EncoderReleaseOnCodecThread: Frames received: " << | 737 ALOGD << "EncoderReleaseOnCodecThread: Frames received: " << |
676 frames_received_ << ". Encoded: " << frames_encoded_ << | 738 frames_received_ << ". Encoded: " << frames_encoded_ << |
677 ". Dropped: " << frames_dropped_; | 739 ". Dropped: " << frames_dropped_; |
678 ScopedLocalRefFrame local_ref_frame(jni); | 740 ScopedLocalRefFrame local_ref_frame(jni); |
679 for (size_t i = 0; i < input_buffers_.size(); ++i) | 741 for (size_t i = 0; i < input_buffers_.size(); ++i) |
680 jni->DeleteGlobalRef(input_buffers_[i]); | 742 jni->DeleteGlobalRef(input_buffers_[i]); |
681 input_buffers_.clear(); | 743 input_buffers_.clear(); |
682 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_); | 744 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_); |
683 CHECK_EXCEPTION(jni); | 745 CHECK_EXCEPTION(jni); |
684 rtc::MessageQueueManager::Clear(this); | 746 rtc::MessageQueueManager::Clear(this); |
685 inited_ = false; | 747 inited_ = false; |
748 use_surface_ = false; | |
686 ALOGD << "EncoderReleaseOnCodecThread done."; | 749 ALOGD << "EncoderReleaseOnCodecThread done."; |
687 return WEBRTC_VIDEO_CODEC_OK; | 750 return WEBRTC_VIDEO_CODEC_OK; |
688 } | 751 } |
689 | 752 |
690 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, | 753 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, |
691 uint32_t frame_rate) { | 754 uint32_t frame_rate) { |
692 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 755 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
693 if (last_set_bitrate_kbps_ == new_bit_rate && | 756 if (last_set_bitrate_kbps_ == new_bit_rate && |
694 last_set_fps_ == frame_rate) { | 757 last_set_fps_ == frame_rate) { |
695 return WEBRTC_VIDEO_CODEC_OK; | 758 return WEBRTC_VIDEO_CODEC_OK; |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
950 | 1013 |
951 void MediaCodecVideoEncoder::OnDroppedFrame() { | 1014 void MediaCodecVideoEncoder::OnDroppedFrame() { |
952 if (scale_) | 1015 if (scale_) |
953 quality_scaler_.ReportDroppedFrame(); | 1016 quality_scaler_.ReportDroppedFrame(); |
954 } | 1017 } |
955 | 1018 |
956 int MediaCodecVideoEncoder::GetTargetFramerate() { | 1019 int MediaCodecVideoEncoder::GetTargetFramerate() { |
957 return scale_ ? quality_scaler_.GetTargetFramerate() : -1; | 1020 return scale_ ? quality_scaler_.GetTargetFramerate() : -1; |
958 } | 1021 } |
959 | 1022 |
960 MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() { | 1023 MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() |
1024 : egl_context_ (nullptr) { | |
961 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 1025 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
962 ScopedLocalRefFrame local_ref_frame(jni); | 1026 ScopedLocalRefFrame local_ref_frame(jni); |
963 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder"); | 1027 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder"); |
964 supported_codecs_.clear(); | 1028 supported_codecs_.clear(); |
965 | 1029 |
966 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod( | 1030 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod( |
967 j_encoder_class, | 1031 j_encoder_class, |
968 GetStaticMethodID(jni, j_encoder_class, "isVp8HwSupported", "()Z")); | 1032 GetStaticMethodID(jni, j_encoder_class, "isVp8HwSupported", "()Z")); |
969 CHECK_EXCEPTION(jni); | 1033 CHECK_EXCEPTION(jni); |
970 if (is_vp8_hw_supported) { | 1034 if (is_vp8_hw_supported) { |
971 ALOGD << "VP8 HW Encoder supported."; | 1035 ALOGD << "VP8 HW Encoder supported."; |
972 supported_codecs_.push_back(VideoCodec(kVideoCodecVP8, "VP8", | 1036 supported_codecs_.push_back(VideoCodec(kVideoCodecVP8, "VP8", |
973 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); | 1037 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); |
974 } | 1038 } |
975 | 1039 |
976 bool is_h264_hw_supported = jni->CallStaticBooleanMethod( | 1040 bool is_h264_hw_supported = jni->CallStaticBooleanMethod( |
977 j_encoder_class, | 1041 j_encoder_class, |
978 GetStaticMethodID(jni, j_encoder_class, "isH264HwSupported", "()Z")); | 1042 GetStaticMethodID(jni, j_encoder_class, "isH264HwSupported", "()Z")); |
979 CHECK_EXCEPTION(jni); | 1043 CHECK_EXCEPTION(jni); |
980 if (is_h264_hw_supported) { | 1044 if (is_h264_hw_supported) { |
981 ALOGD << "H.264 HW Encoder supported."; | 1045 ALOGD << "H.264 HW Encoder supported."; |
982 supported_codecs_.push_back(VideoCodec(kVideoCodecH264, "H264", | 1046 supported_codecs_.push_back(VideoCodec(kVideoCodecH264, "H264", |
983 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); | 1047 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); |
984 } | 1048 } |
985 } | 1049 } |
986 | 1050 |
987 MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {} | 1051 MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {} |
988 | 1052 |
1053 void MediaCodecVideoEncoderFactory::SetEGLContext( | |
1054 JNIEnv* jni, jobject render_egl_context) { | |
1055 ALOGD << "MediaCodecVideoEncoderFactory::SetEGLContext"; | |
1056 if (egl_context_) { | |
1057 jni->DeleteGlobalRef(egl_context_); | |
1058 egl_context_ = NULL; | |
1059 } | |
1060 if (!IsNull(jni, render_egl_context)) { | |
1061 egl_context_ = jni->NewGlobalRef(render_egl_context); | |
1062 if (CheckException(jni)) { | |
1063 ALOGE << "error calling NewGlobalRef for EGL Context."; | |
1064 egl_context_ = NULL; | |
1065 } else { | |
1066 jclass j_egl_context_class = | |
1067 FindClass(jni, "javax/microedition/khronos/egl/EGLContext"); | |
1068 if (!jni->IsInstanceOf(egl_context_, j_egl_context_class)) { | |
1069 ALOGE << "Wrong EGL Context."; | |
1070 jni->DeleteGlobalRef(egl_context_); | |
1071 egl_context_ = NULL; | |
1072 } | |
1073 } | |
1074 } | |
1075 if (egl_context_ == NULL) { | |
1076 ALOGW << "NULL VideoDecoder EGL context - HW surface encoding is disabled."; | |
1077 } | |
1078 } | |
1079 | |
989 webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder( | 1080 webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder( |
990 VideoCodecType type) { | 1081 VideoCodecType type) { |
991 if (supported_codecs_.empty()) { | 1082 if (supported_codecs_.empty()) { |
992 return NULL; | 1083 return NULL; |
993 } | 1084 } |
994 for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin(); | 1085 for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin(); |
995 it != supported_codecs_.end(); ++it) { | 1086 it != supported_codecs_.end(); ++it) { |
996 if (it->type == type) { | 1087 if (it->type == type) { |
997 ALOGD << "Create HW video encoder for type " << (int)type << | 1088 ALOGD << "Create HW video encoder for type " << (int)type << |
998 " (" << it->name << ")."; | 1089 " (" << it->name << ")."; |
999 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type); | 1090 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type, |
1091 egl_context_); | |
1000 } | 1092 } |
1001 } | 1093 } |
1002 return NULL; | 1094 return NULL; |
1003 } | 1095 } |
1004 | 1096 |
1005 const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>& | 1097 const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>& |
1006 MediaCodecVideoEncoderFactory::codecs() const { | 1098 MediaCodecVideoEncoderFactory::codecs() const { |
1007 return supported_codecs_; | 1099 return supported_codecs_; |
1008 } | 1100 } |
1009 | 1101 |
1010 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( | 1102 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( |
1011 webrtc::VideoEncoder* encoder) { | 1103 webrtc::VideoEncoder* encoder) { |
1012 ALOGD << "Destroy video encoder."; | 1104 ALOGD << "Destroy video encoder."; |
1013 delete encoder; | 1105 delete encoder; |
1014 } | 1106 } |
1015 | 1107 |
1016 } // namespace webrtc_jni | 1108 } // namespace webrtc_jni |
1017 | 1109 |
OLD | NEW |