Implement Base::ConstrainNewCodec2.

BUG=1788
R=wu@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/15009004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6743 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org 2014-07-20 14:40:23 +00:00
parent 3edbaaf337
commit 8fdeee6abf
2 changed files with 84 additions and 184 deletions

View File

@ -73,28 +73,8 @@ VideoCodecPref kUlpfecPref = {117, kUlpfecCodecName, -1};
// The formats are sorted by the descending order of width. We use the order to
// find the next format for CPU and bandwidth adaptation.
const VideoFormatPod kDefaultVideoFormat = {
const VideoFormatPod kDefaultMaxVideoFormat = {
640, 400, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY};
const VideoFormatPod kVideoFormats[] = {
{1280, 800, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{1280, 720, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{960, 600, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{960, 540, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
kDefaultVideoFormat,
{640, 360, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{640, 480, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{480, 300, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{480, 270, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{480, 360, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{320, 200, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{320, 180, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{320, 240, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{240, 150, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{240, 135, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{240, 180, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{160, 100, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{160, 90, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
{160, 120, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY}, };
static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs,
const VideoCodec& requested_codec,
@ -107,49 +87,6 @@ static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs,
}
return false;
}
static bool FindBestVideoFormat(int max_width,
int max_height,
int aspect_width,
int aspect_height,
VideoFormat* video_format) {
assert(max_width > 0);
assert(max_height > 0);
assert(aspect_width > 0);
assert(aspect_height > 0);
VideoFormat best_format;
for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) {
const VideoFormat format(kVideoFormats[i]);
// Skip any format that is larger than the local or remote maximums, or
// smaller than the current best match
if (format.width > max_width || format.height > max_height ||
(format.width < best_format.width &&
format.height < best_format.height)) {
continue;
}
// If we don't have any matches yet, this is the best so far.
if (best_format.width == 0) {
best_format = format;
continue;
}
// Prefer closer aspect ratios i.e:
// |format| aspect - requested aspect <
// |best_format| aspect - requested aspect
if (abs(format.width * aspect_height * best_format.height -
aspect_width * format.height * best_format.height) <
abs(best_format.width * aspect_height * format.height -
aspect_width * format.height * best_format.height)) {
best_format = format;
}
}
if (best_format.width != 0) {
*video_format = best_format;
return true;
}
return false;
}
static void AddDefaultFeedbackParams(VideoCodec* codec) {
const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
@ -170,8 +107,8 @@ static bool IsNackEnabled(const VideoCodec& codec) {
static VideoCodec DefaultVideoCodec() {
VideoCodec default_codec(kDefaultVideoCodecPref.payload_type,
kDefaultVideoCodecPref.name,
kDefaultVideoFormat.width,
kDefaultVideoFormat.height,
kDefaultMaxVideoFormat.width,
kDefaultMaxVideoFormat.height,
kDefaultFramerate,
0);
AddDefaultFeedbackParams(&default_codec);
@ -267,7 +204,7 @@ void WebRtcVideoEngine2::Construct(WebRtcVideoChannelFactory* channel_factory,
channel_factory_ = channel_factory;
video_codecs_ = DefaultVideoCodecs();
default_codec_format_ = VideoFormat(kDefaultVideoFormat);
default_codec_format_ = VideoFormat(kDefaultMaxVideoFormat);
rtp_header_extensions_.push_back(
RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension,
@ -320,8 +257,21 @@ bool WebRtcVideoEngine2::SetOptions(const VideoOptions& options) {
bool WebRtcVideoEngine2::SetDefaultEncoderConfig(
const VideoEncoderConfig& config) {
// TODO(pbos): Implement. Should be covered by corresponding unit tests.
LOG(LS_VERBOSE) << "SetDefaultEncoderConfig()";
const VideoCodec& codec = config.max_codec;
// TODO(pbos): Make use of external encoder factory.
if (!GetVideoEncoderFactory()->SupportsCodec(codec)) {
LOG(LS_ERROR) << "SetDefaultEncoderConfig, codec not supported:"
<< codec.ToString();
return false;
}
default_codec_format_ =
VideoFormat(codec.width,
codec.height,
VideoFormat::FpsToInterval(codec.framerate),
FOURCC_ANY);
video_codecs_.clear();
video_codecs_.push_back(codec);
return true;
}
@ -382,17 +332,10 @@ bool WebRtcVideoEngine2::FindCodec(const VideoCodec& in) {
// TODO(pbos): Probe encoder factory to figure out that the codec is supported
// if supported by the encoder factory. Add a corresponding test that fails
// with this code (that doesn't ask the factory).
for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) {
const VideoFormat fmt(kVideoFormats[i]);
if ((in.width != 0 || in.height != 0) &&
(fmt.width != in.width || fmt.height != in.height)) {
continue;
}
for (size_t j = 0; j < video_codecs_.size(); ++j) {
VideoCodec codec(video_codecs_[j].id, video_codecs_[j].name, 0, 0, 0, 0);
if (codec.Matches(in)) {
return true;
}
for (size_t j = 0; j < video_codecs_.size(); ++j) {
VideoCodec codec(video_codecs_[j].id, video_codecs_[j].name, 0, 0, 0, 0);
if (codec.Matches(in)) {
return true;
}
}
return false;
@ -406,7 +349,6 @@ bool WebRtcVideoEngine2::CanSendCodec(const VideoCodec& requested,
const VideoCodec& current,
VideoCodec* out) {
assert(out != NULL);
// TODO(pbos): Implement.
if (requested.width != requested.height &&
(requested.height == 0 || requested.width == 0)) {
@ -420,37 +362,26 @@ bool WebRtcVideoEngine2::CanSendCodec(const VideoCodec& requested,
return false;
}
// Pick the best quality that is within their and our bounds and has the
// correct aspect ratio.
VideoFormat format;
if (requested.width == 0 && requested.height == 0) {
// Special case with resolution 0. The channel should not send frames.
} else {
int max_width = talk_base::_min(requested.width, matching_codec.width);
int max_height = talk_base::_min(requested.height, matching_codec.height);
int aspect_width = max_width;
int aspect_height = max_height;
if (current.width > 0 && current.height > 0) {
aspect_width = current.width;
aspect_height = current.height;
}
if (!FindBestVideoFormat(
max_width, max_height, aspect_width, aspect_height, &format)) {
return false;
}
}
out->id = requested.id;
out->name = requested.name;
out->preference = requested.preference;
out->params = requested.params;
out->framerate =
talk_base::_min(requested.framerate, matching_codec.framerate);
out->width = format.width;
out->height = format.height;
out->params = requested.params;
out->feedback_params = requested.feedback_params;
return true;
out->width = requested.width;
out->height = requested.height;
if (requested.width == 0 && requested.height == 0) {
return true;
}
while (out->width > matching_codec.width) {
out->width /= 2;
out->height /= 2;
}
return out->width > 0 && out->height > 0;
}
bool WebRtcVideoEngine2::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) {

View File

@ -350,8 +350,10 @@ TEST_F(WebRtcVideoEngine2Test, FindCodec) {
vp8_diff_id.id = 97;
EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
// FindCodec ignores the codec size.
// Test that FindCodec can accept uncommon codec size.
cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
EXPECT_FALSE(engine_.FindCodec(vp8_diff_res));
EXPECT_TRUE(engine_.FindCodec(vp8_diff_res));
// PeerConnection doesn't negotiate the resolution at this point.
// Test that FindCodec can handle the case when width/height is 0.
@ -424,6 +426,17 @@ TEST_F(WebRtcVideoEngine2Test, SetSendFailsBeforeSettingCodecs) {
<< "Channel should be stoppable even without set codecs.";
}
class WebRtcVideoEngine2BaseTest
: public VideoEngineTest<cricket::WebRtcVideoEngine2> {
protected:
typedef VideoEngineTest<cricket::WebRtcVideoEngine2> Base;
};
#define WEBRTC_ENGINE_BASE_TEST(test) \
TEST_F(WebRtcVideoEngine2BaseTest, test) { Base::test##Body(); }
WEBRTC_ENGINE_BASE_TEST(ConstrainNewCodec2);
class WebRtcVideoChannel2BaseTest
: public VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> {
protected:
@ -431,118 +444,74 @@ class WebRtcVideoChannel2BaseTest
typedef VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> Base;
};
#define WEBRTC_BASE_TEST(test) \
TEST_F(WebRtcVideoChannel2BaseTest, test) { Base::test(); }
#define WEBRTC_DISABLED_BASE_TEST(test) \
TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_ ## test) { Base::test(); }
// TODO(pbos): Fix WebRtcVideoEngine2BaseTest, where we want CheckCoInitialize.
#if 0
// TODO(juberti): Figure out why ViE is munging the COM refcount.
#ifdef WIN32
TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_CheckCoInitialize) {
WEBRTC_DISABLED_BASE_TEST(CheckCoInitialize) {
Base::CheckCoInitialize();
}
#endif
#endif
TEST_F(WebRtcVideoChannel2BaseTest, SetSend) { Base::SetSend(); }
WEBRTC_BASE_TEST(SetSend);
WEBRTC_BASE_TEST(SetSendWithoutCodecs);
WEBRTC_BASE_TEST(SetSendSetsTransportBufferSizes);
TEST_F(WebRtcVideoChannel2BaseTest, SetSendWithoutCodecs) {
Base::SetSendWithoutCodecs();
}
WEBRTC_BASE_TEST(GetStats);
WEBRTC_BASE_TEST(GetStatsMultipleRecvStreams);
WEBRTC_BASE_TEST(GetStatsMultipleSendStreams);
TEST_F(WebRtcVideoChannel2BaseTest, SetSendSetsTransportBufferSizes) {
Base::SetSendSetsTransportBufferSizes();
}
WEBRTC_BASE_TEST(SetSendBandwidth);
TEST_F(WebRtcVideoChannel2BaseTest, GetStats) { Base::GetStats(); }
WEBRTC_BASE_TEST(SetSendSsrc);
WEBRTC_BASE_TEST(SetSendSsrcAfterSetCodecs);
TEST_F(WebRtcVideoChannel2BaseTest, GetStatsMultipleRecvStreams) {
Base::GetStatsMultipleRecvStreams();
}
WEBRTC_BASE_TEST(SetRenderer);
WEBRTC_BASE_TEST(AddRemoveRecvStreams);
TEST_F(WebRtcVideoChannel2BaseTest, GetStatsMultipleSendStreams) {
Base::GetStatsMultipleSendStreams();
}
WEBRTC_DISABLED_BASE_TEST(AddRemoveRecvStreamAndRender);
TEST_F(WebRtcVideoChannel2BaseTest, SetSendBandwidth) {
Base::SetSendBandwidth();
}
TEST_F(WebRtcVideoChannel2BaseTest, SetSendSsrc) { Base::SetSendSsrc(); }
TEST_F(WebRtcVideoChannel2BaseTest, SetSendSsrcAfterSetCodecs) {
Base::SetSendSsrcAfterSetCodecs();
}
WEBRTC_BASE_TEST(AddRemoveRecvStreamsNoConference);
TEST_F(WebRtcVideoChannel2BaseTest, SetRenderer) { Base::SetRenderer(); }
WEBRTC_BASE_TEST(AddRemoveSendStreams);
TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveRecvStreams) {
Base::AddRemoveRecvStreams();
}
WEBRTC_BASE_TEST(SimulateConference);
TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AddRemoveRecvStreamAndRender) {
Base::AddRemoveRecvStreamAndRender();
}
WEBRTC_BASE_TEST(AddRemoveCapturer);
TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveRecvStreamsNoConference) {
Base::AddRemoveRecvStreamsNoConference();
}
WEBRTC_BASE_TEST(RemoveCapturerWithoutAdd);
TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveSendStreams) {
Base::AddRemoveSendStreams();
}
TEST_F(WebRtcVideoChannel2BaseTest, SimulateConference) {
Base::SimulateConference();
}
TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveCapturer) {
Base::AddRemoveCapturer();
}
TEST_F(WebRtcVideoChannel2BaseTest, RemoveCapturerWithoutAdd) {
Base::RemoveCapturerWithoutAdd();
}
TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveCapturerMultipleSources) {
Base::AddRemoveCapturerMultipleSources();
}
WEBRTC_BASE_TEST(AddRemoveCapturerMultipleSources);
// TODO(pbos): Figure out why this fails so often.
TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_HighAspectHighHeightCapturer) {
Base::HighAspectHighHeightCapturer();
}
WEBRTC_DISABLED_BASE_TEST(HighAspectHighHeightCapturer);
TEST_F(WebRtcVideoChannel2BaseTest, RejectEmptyStreamParams) {
Base::RejectEmptyStreamParams();
}
WEBRTC_BASE_TEST(RejectEmptyStreamParams);
TEST_F(WebRtcVideoChannel2BaseTest, AdaptResolution16x10) {
Base::AdaptResolution16x10();
}
WEBRTC_BASE_TEST(AdaptResolution16x10);
TEST_F(WebRtcVideoChannel2BaseTest, AdaptResolution4x3) {
Base::AdaptResolution4x3();
}
WEBRTC_BASE_TEST(AdaptResolution4x3);
TEST_F(WebRtcVideoChannel2BaseTest, MuteStream) { Base::MuteStream(); }
WEBRTC_BASE_TEST(MuteStream);
TEST_F(WebRtcVideoChannel2BaseTest, MultipleSendStreams) {
Base::MultipleSendStreams();
}
WEBRTC_BASE_TEST(MultipleSendStreams);
// TODO(juberti): Restore this test once we support sending 0 fps.
TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AdaptDropAllFrames) {
Base::AdaptDropAllFrames();
}
WEBRTC_DISABLED_BASE_TEST(AdaptDropAllFrames);
// TODO(juberti): Understand why we get decode errors on this test.
TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AdaptFramerate) {
Base::AdaptFramerate();
}
WEBRTC_DISABLED_BASE_TEST(AdaptFramerate);
TEST_F(WebRtcVideoChannel2BaseTest, SetSendStreamFormat0x0) {
Base::SetSendStreamFormat0x0();
}
WEBRTC_BASE_TEST(SetSendStreamFormat0x0);
// TODO(zhurunz): Fix the flakey test.
TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_SetSendStreamFormat) {
Base::SetSendStreamFormat();
}
WEBRTC_DISABLED_BASE_TEST(SetSendStreamFormat);
TEST_F(WebRtcVideoChannel2BaseTest, TwoStreamsSendAndReceive) {
Base::TwoStreamsSendAndReceive(kVp8Codec);