| Index: talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
|
| diff --git a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
|
| index a74044600a754a2fb8ee1c74dcade55b9d557f66..f6a3b650a6b8aaf481fa941e3bbb777a09dc84b6 100644
|
| --- a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
|
| +++ b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
|
| @@ -33,6 +33,7 @@
|
| #include "webrtc/base/checks.h"
|
| #include "webrtc/base/logging.h"
|
| #include "webrtc/base/thread.h"
|
| +#include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h"
|
| #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
|
| #include "webrtc/modules/video_coding/utility/include/quality_scaler.h"
|
| #include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h"
|
| @@ -199,10 +200,12 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
|
| bool drop_next_input_frame_;
|
| // Global references; must be deleted in Release().
|
| std::vector<jobject> input_buffers_;
|
| - scoped_ptr<webrtc::QualityScaler> quality_scaler_;
|
| + webrtc::QualityScaler quality_scaler_;
|
| // Dynamic resolution change, off by default.
|
| bool scale_;
|
| - int updated_framerate_;
|
| +
|
| + // H264 bitstream parser, used to extract QP from encoded bitstreams.
|
| + webrtc::H264BitstreamParser h264_bitstream_parser_;
|
| };
|
|
|
| MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
|
| @@ -217,7 +220,6 @@ MediaCodecVideoEncoder::MediaCodecVideoEncoder(
|
| inited_(false),
|
| picture_id_(0),
|
| codec_thread_(new Thread()),
|
| - quality_scaler_(new webrtc::QualityScaler()),
|
| j_media_codec_video_encoder_class_(
|
| jni,
|
| FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
|
| @@ -283,10 +285,6 @@ int32_t MediaCodecVideoEncoder::InitEncode(
|
| size_t /* max_payload_size */) {
|
| const int kMinWidth = 320;
|
| const int kMinHeight = 180;
|
| - // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
|
| - // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is
|
| - // always = 127. Note that in SW, QP is that of the user-level range [0, 63].
|
| - const int kMaxQP = 127;
|
| const int kLowQpThresholdDenominator = 3;
|
| if (codec_settings == NULL) {
|
| ALOGE("NULL VideoCodec instance");
|
| @@ -298,18 +296,28 @@ int32_t MediaCodecVideoEncoder::InitEncode(
|
| << codecType_;
|
|
|
| ALOGD("InitEncode request");
|
| -
|
| scale_ = webrtc::field_trial::FindFullName(
|
| "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled";
|
| ALOGD("Automatic resize: %s", scale_ ? "enabled" : "disabled");
|
| -
|
| - if (scale_ && codecType_ == kVideoCodecVP8) {
|
| - quality_scaler_->Init(kMaxQP / kLowQpThresholdDenominator, true);
|
| - quality_scaler_->SetMinResolution(kMinWidth, kMinHeight);
|
| - quality_scaler_->ReportFramerate(codec_settings->maxFramerate);
|
| - updated_framerate_ = codec_settings->maxFramerate;
|
| - } else {
|
| - updated_framerate_ = -1;
|
| + if (scale_) {
|
| + if (codecType_ == kVideoCodecVP8) {
|
| + // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
|
| + // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is
|
| + // always = 127. Note that in SW, QP is that of the user-level range [0,
|
| + // 63].
|
| + const int kMaxQp = 127;
|
| + quality_scaler_.Init(kMaxQp / kLowQpThresholdDenominator, true);
|
| + } else if (codecType_ == kVideoCodecH264) {
|
| + // H264 QP is in the range [0, 51].
|
| + const int kMaxQp = 51;
|
| + quality_scaler_.Init(kMaxQp / kLowQpThresholdDenominator, true);
|
| + } else {
|
| + // When adding codec support to additional hardware codecs, also configure
|
| + // their QP thresholds for scaling.
|
| + RTC_NOTREACHED() << "Unsupported codec without configured QP thresholds.";
|
| + }
|
| + quality_scaler_.SetMinResolution(kMinWidth, kMinHeight);
|
| + quality_scaler_.ReportFramerate(codec_settings->maxFramerate);
|
| }
|
| return codec_thread_->Invoke<int32_t>(
|
| Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
|
| @@ -349,9 +357,9 @@ int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
|
|
|
| int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
|
| uint32_t frame_rate) {
|
| - if (scale_ && codecType_ == kVideoCodecVP8) {
|
| - quality_scaler_->ReportFramerate(frame_rate);
|
| - }
|
| + if (scale_)
|
| + quality_scaler_.ReportFramerate(frame_rate);
|
| +
|
| return codec_thread_->Invoke<int32_t>(
|
| Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
|
| this,
|
| @@ -507,12 +515,11 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
|
|
|
| RTC_CHECK(frame_types->size() == 1) << "Unexpected stream count";
|
| // Check framerate before spatial resolution change.
|
| - if (scale_ && codecType_ == kVideoCodecVP8) {
|
| - quality_scaler_->OnEncodeFrame(frame);
|
| - updated_framerate_ = quality_scaler_->GetTargetFramerate();
|
| - }
|
| - const VideoFrame& input_frame = (scale_ && codecType_ == kVideoCodecVP8) ?
|
| - quality_scaler_->GetScaledFrame(frame) : frame;
|
| + if (scale_)
|
| + quality_scaler_.OnEncodeFrame(frame);
|
| +
|
| + const VideoFrame& input_frame =
|
| + scale_ ? quality_scaler_.GetScaledFrame(frame) : frame;
|
|
|
| if (input_frame.width() != width_ || input_frame.height() != height_) {
|
| ALOGD("Frame resolution change from %d x %d to %d x %d",
|
| @@ -723,9 +730,6 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
|
| last_input_timestamp_ms_ - last_output_timestamp_ms_,
|
| frame_encoding_time_ms);
|
|
|
| - if (payload_size && scale_ && codecType_ == kVideoCodecVP8)
|
| - quality_scaler_->ReportQP(webrtc::vp8::GetQP(payload));
|
| -
|
| // Calculate and print encoding statistics - every 3 seconds.
|
| frames_encoded_++;
|
| current_frames_++;
|
| @@ -781,7 +785,15 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
|
| header.fragmentationLength[0] = image->_length;
|
| header.fragmentationPlType[0] = 0;
|
| header.fragmentationTimeDiff[0] = 0;
|
| + if (scale_)
|
| + quality_scaler_.ReportQP(webrtc::vp8::GetQP(payload));
|
| } else if (codecType_ == kVideoCodecH264) {
|
| + if (scale_) {
|
| + h264_bitstream_parser_.ParseBitstream(payload, payload_size);
|
| + int qp;
|
| + if (h264_bitstream_parser_.GetLastSliceQp(&qp))
|
| + quality_scaler_.ReportQP(qp);
|
| + }
|
| // For H.264 search for start codes.
|
| int32_t scPositions[MAX_NALUS_PERFRAME + 1] = {};
|
| int32_t scPositionsLength = 0;
|
| @@ -871,12 +883,12 @@ int32_t MediaCodecVideoEncoder::NextNaluPosition(
|
| }
|
|
|
| void MediaCodecVideoEncoder::OnDroppedFrame() {
|
| - if (scale_ && codecType_ == kVideoCodecVP8)
|
| - quality_scaler_->ReportDroppedFrame();
|
| + if (scale_)
|
| + quality_scaler_.ReportDroppedFrame();
|
| }
|
|
|
| int MediaCodecVideoEncoder::GetTargetFramerate() {
|
| - return updated_framerate_;
|
| + return scale_ ? quality_scaler_.GetTargetFramerate() : -1;
|
| }
|
|
|
| MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
|
|
|