Index: talk/app/webrtc/java/jni/androidmediadecoder_jni.cc |
diff --git a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc |
index a67dd502ffc433dac2e5b63e2d5a8f079aee66c9..4f7445ef4317ad8fcd0a7541b92ebea84dfaab8e 100644 |
--- a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc |
+++ b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc |
@@ -35,7 +35,9 @@ |
#include "webrtc/base/bind.h" |
#include "webrtc/base/checks.h" |
#include "webrtc/base/logging.h" |
+#include "webrtc/base/scoped_ref_ptr.h" |
#include "webrtc/base/thread.h" |
+#include "webrtc/common_video/interface/i420_buffer_pool.h" |
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" |
#include "webrtc/system_wrappers/interface/logcat_trace_context.h" |
#include "webrtc/system_wrappers/interface/tick_util.h" |
@@ -106,7 +108,7 @@ class MediaCodecVideoDecoder : public webrtc::VideoDecoder, |
bool sw_fallback_required_; |
bool use_surface_; |
VideoCodec codec_; |
- VideoFrame decoded_image_; |
+ webrtc::I420BufferPool decoded_frame_pool_; |
NativeHandleImpl native_handle_; |
DecodedImageCallback* callback_; |
int frames_received_; // Number of frames received by decoder. |
@@ -120,9 +122,6 @@ class MediaCodecVideoDecoder : public webrtc::VideoDecoder, |
std::vector<int64_t> ntp_times_ms_; |
std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to |
// decoder input. |
- int32_t output_timestamp_; // Last output frame timestamp from timestamps_ Q. |
- int64_t output_ntp_time_ms_; // Last output frame ntp time from |
- // ntp_times_ms_ queue. |
// State that is constant for the lifetime of this object once the ctor |
// returns. |
@@ -331,8 +330,6 @@ int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() { |
current_frames_ = 0; |
current_bytes_ = 0; |
current_decoding_time_ms_ = 0; |
- output_timestamp_ = 0; |
- output_ntp_time_ms_ = 0; |
timestamps_.clear(); |
ntp_times_ms_.clear(); |
frame_rtc_times_ms_.clear(); |
@@ -600,9 +597,14 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs( |
int texture_id = GetIntField(jni, *j_media_codec_video_decoder_, |
j_textureID_field_); |
- // Extract data from Java ByteBuffer and create output yuv420 frame - |
- // for non surface decoding only. |
- if (!use_surface_) { |
+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer; |
+ if (use_surface_) { |
+ native_handle_.SetTextureObject(surface_texture_, texture_id); |
+ frame_buffer = new rtc::RefCountedObject<JniNativeHandleBuffer>( |
+ &native_handle_, width, height); |
+ } else { |
+ // Extract data from Java ByteBuffer and create output yuv420 frame - |
+ // for non surface decoding only. |
if (output_buffer_size < width * height * 3 / 2) { |
ALOGE("Insufficient output buffer size: %d", output_buffer_size); |
return false; |
@@ -619,37 +621,50 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs( |
payload += output_buffer_offset; |
// Create yuv420 frame. |
+ frame_buffer = decoded_frame_pool_.CreateBuffer(width, height); |
if (color_format == COLOR_FormatYUV420Planar) { |
- decoded_image_.CreateFrame( |
- payload, |
- payload + (stride * slice_height), |
- payload + (5 * stride * slice_height / 4), |
- width, height, |
- stride, stride / 2, stride / 2); |
+ RTC_CHECK_EQ(0, stride % 2); |
+ RTC_CHECK_EQ(0, slice_height % 2); |
+ const int uv_stride = stride / 2; |
+ const int u_slice_height = slice_height / 2; |
+ const uint8_t* y_ptr = payload; |
+ const uint8_t* u_ptr = y_ptr + stride * slice_height; |
+ const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height; |
+ libyuv::I420Copy(y_ptr, stride, |
+ u_ptr, uv_stride, |
+ v_ptr, uv_stride, |
+ frame_buffer->MutableData(webrtc::kYPlane), |
+ frame_buffer->stride(webrtc::kYPlane), |
+ frame_buffer->MutableData(webrtc::kUPlane), |
+ frame_buffer->stride(webrtc::kUPlane), |
+ frame_buffer->MutableData(webrtc::kVPlane), |
+ frame_buffer->stride(webrtc::kVPlane), |
+ width, height); |
} else { |
// All other supported formats are nv12. |
- decoded_image_.CreateEmptyFrame(width, height, width, |
- width / 2, width / 2); |
+ const uint8_t* y_ptr = payload; |
+ const uint8_t* uv_ptr = y_ptr + stride * slice_height; |
libyuv::NV12ToI420( |
- payload, stride, |
- payload + stride * slice_height, stride, |
- decoded_image_.buffer(webrtc::kYPlane), |
- decoded_image_.stride(webrtc::kYPlane), |
- decoded_image_.buffer(webrtc::kUPlane), |
- decoded_image_.stride(webrtc::kUPlane), |
- decoded_image_.buffer(webrtc::kVPlane), |
- decoded_image_.stride(webrtc::kVPlane), |
+ y_ptr, stride, |
+ uv_ptr, stride, |
+ frame_buffer->MutableData(webrtc::kYPlane), |
+ frame_buffer->stride(webrtc::kYPlane), |
+ frame_buffer->MutableData(webrtc::kUPlane), |
+ frame_buffer->stride(webrtc::kUPlane), |
+ frame_buffer->MutableData(webrtc::kVPlane), |
+ frame_buffer->stride(webrtc::kVPlane), |
width, height); |
} |
} |
+ VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0); |
// Get frame timestamps from a queue. |
if (timestamps_.size() > 0) { |
- output_timestamp_ = timestamps_.front(); |
+ decoded_frame.set_timestamp(timestamps_.front()); |
timestamps_.erase(timestamps_.begin()); |
} |
if (ntp_times_ms_.size() > 0) { |
- output_ntp_time_ms_ = ntp_times_ms_.front(); |
+ decoded_frame.set_ntp_time_ms(ntp_times_ms_.front()); |
ntp_times_ms_.erase(ntp_times_ms_.begin()); |
} |
int64_t frame_decoding_time_ms = 0; |
@@ -689,19 +704,7 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs( |
} |
// Callback - output decoded frame. |
- int32_t callback_status = WEBRTC_VIDEO_CODEC_OK; |
- if (use_surface_) { |
- native_handle_.SetTextureObject(surface_texture_, texture_id); |
- VideoFrame texture_image(new rtc::RefCountedObject<JniNativeHandleBuffer>( |
- &native_handle_, width, height), |
- output_timestamp_, 0, webrtc::kVideoRotation_0); |
- texture_image.set_ntp_time_ms(output_ntp_time_ms_); |
- callback_status = callback_->Decoded(texture_image); |
- } else { |
- decoded_image_.set_timestamp(output_timestamp_); |
- decoded_image_.set_ntp_time_ms(output_ntp_time_ms_); |
- callback_status = callback_->Decoded(decoded_image_); |
- } |
+ const int32_t callback_status = callback_->Decoded(decoded_frame); |
if (callback_status > 0) { |
ALOGE("callback error"); |
} |