Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(218)

Side by Side Diff: talk/app/webrtc/java/jni/androidmediaencoder_jni.cc

Issue 1451953002: Preliminary support of VP9 HW encoder on Android. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Use warnings in log Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 using rtc::scoped_ptr; 50 using rtc::scoped_ptr;
51 51
52 using webrtc::CodecSpecificInfo; 52 using webrtc::CodecSpecificInfo;
53 using webrtc::EncodedImage; 53 using webrtc::EncodedImage;
54 using webrtc::VideoFrame; 54 using webrtc::VideoFrame;
55 using webrtc::RTPFragmentationHeader; 55 using webrtc::RTPFragmentationHeader;
56 using webrtc::VideoCodec; 56 using webrtc::VideoCodec;
57 using webrtc::VideoCodecType; 57 using webrtc::VideoCodecType;
58 using webrtc::kVideoCodecH264; 58 using webrtc::kVideoCodecH264;
59 using webrtc::kVideoCodecVP8; 59 using webrtc::kVideoCodecVP8;
60 using webrtc::kVideoCodecVP9;
60 61
61 namespace webrtc_jni { 62 namespace webrtc_jni {
62 63
63 // H.264 start code length. 64 // H.264 start code length.
64 #define H264_SC_LENGTH 4 65 #define H264_SC_LENGTH 4
65 // Maximum allowed NALUs in one output frame. 66 // Maximum allowed NALUs in one output frame.
66 #define MAX_NALUS_PERFRAME 32 67 #define MAX_NALUS_PERFRAME 32
67 // Maximum supported HW video encoder resolution. 68 // Maximum supported HW video encoder resolution.
68 #define MAX_VIDEO_WIDTH 1280 69 #define MAX_VIDEO_WIDTH 1280
69 #define MAX_VIDEO_HEIGHT 1280 70 #define MAX_VIDEO_HEIGHT 1280
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 // and the next Encode() call being ignored. 207 // and the next Encode() call being ignored.
207 bool drop_next_input_frame_; 208 bool drop_next_input_frame_;
208 // Global references; must be deleted in Release(). 209 // Global references; must be deleted in Release().
209 std::vector<jobject> input_buffers_; 210 std::vector<jobject> input_buffers_;
210 webrtc::QualityScaler quality_scaler_; 211 webrtc::QualityScaler quality_scaler_;
211 // Dynamic resolution change, off by default. 212 // Dynamic resolution change, off by default.
212 bool scale_; 213 bool scale_;
213 214
214 // H264 bitstream parser, used to extract QP from encoded bitstreams. 215 // H264 bitstream parser, used to extract QP from encoded bitstreams.
215 webrtc::H264BitstreamParser h264_bitstream_parser_; 216 webrtc::H264BitstreamParser h264_bitstream_parser_;
217
218 // VP9 variables to populate codec specific structure.
219 webrtc::GofInfoVP9 gof_; // Contains each frame's temporal information for
220 // non-flexible VP9 mode.
221 uint8_t tl0_pic_idx_;
222 size_t gof_idx_;
216 }; 223 };
217 224
218 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { 225 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
219 // Call Release() to ensure no more callbacks to us after we are deleted. 226 // Call Release() to ensure no more callbacks to us after we are deleted.
220 Release(); 227 Release();
221 } 228 }
222 229
223 MediaCodecVideoEncoder::MediaCodecVideoEncoder( 230 MediaCodecVideoEncoder::MediaCodecVideoEncoder(
224 JNIEnv* jni, VideoCodecType codecType) : 231 JNIEnv* jni, VideoCodecType codecType) :
225 codecType_(codecType), 232 codecType_(codecType),
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 if (codec_settings == NULL) { 307 if (codec_settings == NULL) {
301 ALOGE << "NULL VideoCodec instance"; 308 ALOGE << "NULL VideoCodec instance";
302 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 309 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
303 } 310 }
304 // Factory should guard against other codecs being used with us. 311 // Factory should guard against other codecs being used with us.
305 RTC_CHECK(codec_settings->codecType == codecType_) 312 RTC_CHECK(codec_settings->codecType == codecType_)
306 << "Unsupported codec " << codec_settings->codecType << " for " 313 << "Unsupported codec " << codec_settings->codecType << " for "
307 << codecType_; 314 << codecType_;
308 315
309 ALOGD << "InitEncode request"; 316 ALOGD << "InitEncode request";
310 scale_ = webrtc::field_trial::FindFullName( 317 if (codecType_ == kVideoCodecVP9) {
311 "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled"; 318 scale_ = false;
319 } else {
320 scale_ = webrtc::field_trial::FindFullName(
magjed_webrtc 2015/11/18 13:28:24 I would prefer scale_ = codecType_ != kVideoCodec
AlexG 2015/11/18 19:03:51 Done.
321 "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled";
322 }
312 ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled"); 323 ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled");
313 if (scale_) { 324 if (scale_) {
314 if (codecType_ == kVideoCodecVP8) { 325 if (codecType_ == kVideoCodecVP8) {
315 // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the 326 // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
316 // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is 327 // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is
317 // always = 127. Note that in SW, QP is that of the user-level range [0, 328 // always = 127. Note that in SW, QP is that of the user-level range [0,
318 // 63]. 329 // 63].
319 const int kMaxQp = 127; 330 const int kMaxQp = 127;
320 // TODO(pbos): Investigate whether high-QP thresholds make sense for VP8. 331 // TODO(pbos): Investigate whether high-QP thresholds make sense for VP8.
321 // This effectively disables high QP as VP8 QP can't go above this 332 // This effectively disables high QP as VP8 QP can't go above this
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 current_encoding_time_ms_ = 0; 462 current_encoding_time_ms_ = 0;
452 last_input_timestamp_ms_ = -1; 463 last_input_timestamp_ms_ = -1;
453 last_output_timestamp_ms_ = -1; 464 last_output_timestamp_ms_ = -1;
454 output_timestamp_ = 0; 465 output_timestamp_ = 0;
455 output_render_time_ms_ = 0; 466 output_render_time_ms_ = 0;
456 timestamps_.clear(); 467 timestamps_.clear();
457 render_times_ms_.clear(); 468 render_times_ms_.clear();
458 frame_rtc_times_ms_.clear(); 469 frame_rtc_times_ms_.clear();
459 drop_next_input_frame_ = false; 470 drop_next_input_frame_ = false;
460 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; 471 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
472 gof_.SetGofInfoVP9(webrtc::TemporalStructureMode::kTemporalStructureMode1);
473 tl0_pic_idx_ = static_cast<uint8_t>(rand());
magjed_webrtc 2015/11/18 13:28:24 I'm curious, do you know where srand() is called?
AlexG 2015/11/18 19:03:51 Done. Added srand() to ctor
474 gof_idx_ = 0;
461 475
462 // We enforce no extra stride/padding in the format creation step. 476 // We enforce no extra stride/padding in the format creation step.
463 jobject j_video_codec_enum = JavaEnumFromIndex( 477 jobject j_video_codec_enum = JavaEnumFromIndex(
464 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); 478 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_);
465 const bool encode_status = jni->CallBooleanMethod( 479 const bool encode_status = jni->CallBooleanMethod(
466 *j_media_codec_video_encoder_, j_init_encode_method_, 480 *j_media_codec_video_encoder_, j_init_encode_method_,
467 j_video_codec_enum, width, height, kbps, fps); 481 j_video_codec_enum, width, height, kbps, fps);
468 if (!encode_status) { 482 if (!encode_status) {
469 ALOGE << "Failed to configure encoder."; 483 ALOGE << "Failed to configure encoder.";
470 return WEBRTC_VIDEO_CODEC_ERROR; 484 return WEBRTC_VIDEO_CODEC_ERROR;
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 memset(&info, 0, sizeof(info)); 843 memset(&info, 0, sizeof(info));
830 info.codecType = codecType_; 844 info.codecType = codecType_;
831 if (codecType_ == kVideoCodecVP8) { 845 if (codecType_ == kVideoCodecVP8) {
832 info.codecSpecific.VP8.pictureId = picture_id_; 846 info.codecSpecific.VP8.pictureId = picture_id_;
833 info.codecSpecific.VP8.nonReference = false; 847 info.codecSpecific.VP8.nonReference = false;
834 info.codecSpecific.VP8.simulcastIdx = 0; 848 info.codecSpecific.VP8.simulcastIdx = 0;
835 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx; 849 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx;
836 info.codecSpecific.VP8.layerSync = false; 850 info.codecSpecific.VP8.layerSync = false;
837 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx; 851 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
838 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx; 852 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
839 picture_id_ = (picture_id_ + 1) & 0x7FFF; 853 } else if (codecType_ == kVideoCodecVP9) {
854 if (key_frame) {
855 gof_idx_ = 0;
856 }
857 info.codecSpecific.VP9.picture_id = picture_id_;
858 info.codecSpecific.VP9.inter_pic_predicted = key_frame ? false : true;
859 info.codecSpecific.VP9.flexible_mode = false;
860 info.codecSpecific.VP9.ss_data_available = key_frame ? true : false;
861 info.codecSpecific.VP9.tl0_pic_idx = tl0_pic_idx_++;
862 info.codecSpecific.VP9.temporal_idx = webrtc::kNoTemporalIdx;
863 info.codecSpecific.VP9.spatial_idx = webrtc::kNoSpatialIdx;
864 info.codecSpecific.VP9.temporal_up_switch = true;
865 info.codecSpecific.VP9.inter_layer_predicted = false;
866 info.codecSpecific.VP9.gof_idx =
867 static_cast<uint8_t>(gof_idx_++ % gof_.num_frames_in_gof);
868 info.codecSpecific.VP9.num_spatial_layers = 1;
869 info.codecSpecific.VP9.spatial_layer_resolution_present = false;
870 if (info.codecSpecific.VP9.ss_data_available) {
871 info.codecSpecific.VP9.spatial_layer_resolution_present = true;
872 info.codecSpecific.VP9.width[0] = width_;
873 info.codecSpecific.VP9.height[0] = height_;
874 info.codecSpecific.VP9.gof.CopyGofInfoVP9(gof_);
875 }
840 } 876 }
877 picture_id_ = (picture_id_ + 1) & 0x7FFF;
841 878
842 // Generate a header describing a single fragment. 879 // Generate a header describing a single fragment.
843 webrtc::RTPFragmentationHeader header; 880 webrtc::RTPFragmentationHeader header;
844 memset(&header, 0, sizeof(header)); 881 memset(&header, 0, sizeof(header));
845 if (codecType_ == kVideoCodecVP8) { 882 if (codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecVP9) {
846 header.VerifyAndAllocateFragmentationHeader(1); 883 header.VerifyAndAllocateFragmentationHeader(1);
847 header.fragmentationOffset[0] = 0; 884 header.fragmentationOffset[0] = 0;
848 header.fragmentationLength[0] = image->_length; 885 header.fragmentationLength[0] = image->_length;
849 header.fragmentationPlType[0] = 0; 886 header.fragmentationPlType[0] = 0;
850 header.fragmentationTimeDiff[0] = 0; 887 header.fragmentationTimeDiff[0] = 0;
851 if (scale_) { 888 if (codecType_ == kVideoCodecVP8 && scale_) {
magjed_webrtc 2015/11/18 13:28:24 Revert this change, and only check |scale_|.
AlexG 2015/11/18 19:03:51 I think it is a little cleaner to keep this check
magjed_webrtc 2015/11/19 08:10:03 I see, I didn't realize it was vp8 specific scalin
852 int qp; 889 int qp;
853 if (webrtc::vp8::GetQp(payload, payload_size, &qp)) 890 if (webrtc::vp8::GetQp(payload, payload_size, &qp))
854 quality_scaler_.ReportQP(qp); 891 quality_scaler_.ReportQP(qp);
855 } 892 }
856 } else if (codecType_ == kVideoCodecH264) { 893 } else if (codecType_ == kVideoCodecH264) {
857 if (scale_) { 894 if (scale_) {
858 h264_bitstream_parser_.ParseBitstream(payload, payload_size); 895 h264_bitstream_parser_.ParseBitstream(payload, payload_size);
859 int qp; 896 int qp;
860 if (h264_bitstream_parser_.GetLastSliceQp(&qp)) 897 if (h264_bitstream_parser_.GetLastSliceQp(&qp))
861 quality_scaler_.ReportQP(qp); 898 quality_scaler_.ReportQP(qp);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
966 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod( 1003 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
967 j_encoder_class, 1004 j_encoder_class,
968 GetStaticMethodID(jni, j_encoder_class, "isVp8HwSupported", "()Z")); 1005 GetStaticMethodID(jni, j_encoder_class, "isVp8HwSupported", "()Z"));
969 CHECK_EXCEPTION(jni); 1006 CHECK_EXCEPTION(jni);
970 if (is_vp8_hw_supported) { 1007 if (is_vp8_hw_supported) {
971 ALOGD << "VP8 HW Encoder supported."; 1008 ALOGD << "VP8 HW Encoder supported.";
972 supported_codecs_.push_back(VideoCodec(kVideoCodecVP8, "VP8", 1009 supported_codecs_.push_back(VideoCodec(kVideoCodecVP8, "VP8",
973 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); 1010 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS));
974 } 1011 }
975 1012
1013 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
1014 j_encoder_class,
1015 GetStaticMethodID(jni, j_encoder_class, "isVp9HwSupported", "()Z"));
1016 CHECK_EXCEPTION(jni);
1017 if (is_vp9_hw_supported) {
1018 ALOGD << "VP9 HW Encoder supported.";
1019 supported_codecs_.push_back(VideoCodec(kVideoCodecVP9, "VP9",
1020 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS));
1021 }
1022
976 bool is_h264_hw_supported = jni->CallStaticBooleanMethod( 1023 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
977 j_encoder_class, 1024 j_encoder_class,
978 GetStaticMethodID(jni, j_encoder_class, "isH264HwSupported", "()Z")); 1025 GetStaticMethodID(jni, j_encoder_class, "isH264HwSupported", "()Z"));
979 CHECK_EXCEPTION(jni); 1026 CHECK_EXCEPTION(jni);
980 if (is_h264_hw_supported) { 1027 if (is_h264_hw_supported) {
981 ALOGD << "H.264 HW Encoder supported."; 1028 ALOGD << "H.264 HW Encoder supported.";
982 supported_codecs_.push_back(VideoCodec(kVideoCodecH264, "H264", 1029 supported_codecs_.push_back(VideoCodec(kVideoCodecH264, "H264",
983 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); 1030 MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS));
984 } 1031 }
985 } 1032 }
986 1033
987 MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {} 1034 MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
988 1035
989 webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder( 1036 webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
990 VideoCodecType type) { 1037 VideoCodecType type) {
991 if (supported_codecs_.empty()) { 1038 if (supported_codecs_.empty()) {
1039 ALOGW << "No HW video encoder for type " << (int)type;
992 return NULL; 1040 return NULL;
993 } 1041 }
994 for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin(); 1042 for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin();
995 it != supported_codecs_.end(); ++it) { 1043 it != supported_codecs_.end(); ++it) {
996 if (it->type == type) { 1044 if (it->type == type) {
997 ALOGD << "Create HW video encoder for type " << (int)type << 1045 ALOGD << "Create HW video encoder for type " << (int)type <<
998 " (" << it->name << ")."; 1046 " (" << it->name << ").";
999 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type); 1047 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type);
1000 } 1048 }
1001 } 1049 }
1050 ALOGW << "Can not find HW video encoder for type " << (int)type;
1002 return NULL; 1051 return NULL;
1003 } 1052 }
1004 1053
1005 const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>& 1054 const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1006 MediaCodecVideoEncoderFactory::codecs() const { 1055 MediaCodecVideoEncoderFactory::codecs() const {
1007 return supported_codecs_; 1056 return supported_codecs_;
1008 } 1057 }
1009 1058
1010 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( 1059 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1011 webrtc::VideoEncoder* encoder) { 1060 webrtc::VideoEncoder* encoder) {
1012 ALOGD << "Destroy video encoder."; 1061 ALOGD << "Destroy video encoder.";
1013 delete encoder; 1062 delete encoder;
1014 } 1063 }
1015 1064
1016 } // namespace webrtc_jni 1065 } // namespace webrtc_jni
1017 1066
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/jni/androidmediadecoder_jni.cc ('k') | talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698