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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |