Commit f05067ab authored by Markus Handell's avatar Markus Handell Committed by Commit Bot

MediaRecorder passthru: Err out on codec change.

Our WebmMuxer doesn't support changing saved format mid-track. This
change causes calls to MediaRecorder OnError which emits an event and
causes recording to stop.

Bug: 1013590
Change-Id: If1dd020dc61980feff33883a4967ac24fc0e0255
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1893856Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Commit-Queue: Markus Handell <handellm@google.com>
Cr-Commit-Position: refs/heads/master@{#722512}
parent 784617d3
...@@ -525,6 +525,17 @@ void MediaRecorderHandler::HandleEncodedVideo( ...@@ -525,6 +525,17 @@ void MediaRecorderHandler::HandleEncodedVideo(
recorder_->OnError("Amount of tracks in MediaStream has changed."); recorder_->OnError("Amount of tracks in MediaStream has changed.");
return; return;
} }
if (!last_seen_codec_.has_value())
last_seen_codec_ = params.codec;
if (*last_seen_codec_ != params.codec) {
recorder_->OnError(
String::Format("Video codec changed from %s to %s",
media::GetCodecName(*last_seen_codec_).c_str(),
media::GetCodecName(params.codec).c_str()));
return;
}
if (!webm_muxer_) if (!webm_muxer_)
return; return;
if (!webm_muxer_->OnEncodedVideo(params, std::move(encoded_data), if (!webm_muxer_->OnEncodedVideo(params, std::move(encoded_data),
......
...@@ -138,6 +138,9 @@ class MODULES_EXPORT MediaRecorderHandler final ...@@ -138,6 +138,9 @@ class MODULES_EXPORT MediaRecorderHandler final
base::TimeDelta timeslice_; base::TimeDelta timeslice_;
base::TimeTicks slice_origin_timestamp_; base::TimeTicks slice_origin_timestamp_;
// The last seen video codec of the last received encoded video frame.
base::Optional<media::VideoCodec> last_seen_codec_;
bool recording_; bool recording_;
// The MediaStream being recorded. // The MediaStream being recorded.
Member<MediaStreamDescriptor> media_stream_; Member<MediaStreamDescriptor> media_stream_;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/modules/mediarecorder/fake_encoded_video_frame.h" #include "third_party/blink/renderer/modules/mediarecorder/fake_encoded_video_frame.h"
#include "third_party/blink/renderer/modules/mediarecorder/media_recorder.h" #include "third_party/blink/renderer/modules/mediarecorder/media_recorder.h"
...@@ -33,6 +34,7 @@ using ::testing::AtLeast; ...@@ -33,6 +34,7 @@ using ::testing::AtLeast;
using ::testing::Ge; using ::testing::Ge;
using ::testing::Gt; using ::testing::Gt;
using ::testing::InSequence; using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::Lt; using ::testing::Lt;
using ::testing::Mock; using ::testing::Mock;
using ::testing::Return; using ::testing::Return;
...@@ -542,7 +544,8 @@ class MediaRecorderHandlerPassthroughTest ...@@ -542,7 +544,8 @@ class MediaRecorderHandlerPassthroughTest
~MediaRecorderHandlerPassthroughTest() { ~MediaRecorderHandlerPassthroughTest() {
registry_.reset(); registry_.reset();
ThreadState::Current()->CollectAllGarbageForTesting(); media_recorder_handler_ = nullptr;
WebHeap::CollectAllGarbageForTesting();
} }
void OnVideoFrameForTesting(scoped_refptr<EncodedVideoFrame> frame) { void OnVideoFrameForTesting(scoped_refptr<EncodedVideoFrame> frame) {
...@@ -552,7 +555,7 @@ class MediaRecorderHandlerPassthroughTest ...@@ -552,7 +555,7 @@ class MediaRecorderHandlerPassthroughTest
ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_; ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
MockMediaStreamRegistry registry_; MockMediaStreamRegistry registry_;
MockMediaStreamVideoSource* video_source_ = 0; MockMediaStreamVideoSource* video_source_ = nullptr;
Persistent<MediaRecorderHandler> media_recorder_handler_; Persistent<MediaRecorderHandler> media_recorder_handler_;
private: private:
...@@ -596,6 +599,46 @@ TEST_P(MediaRecorderHandlerPassthroughTest, PassesThrough) { ...@@ -596,6 +599,46 @@ TEST_P(MediaRecorderHandlerPassthroughTest, PassesThrough) {
media_recorder_handler_ = nullptr; media_recorder_handler_ = nullptr;
} }
TEST_F(MediaRecorderHandlerPassthroughTest, ErrorsOutOnCodecSwitch) {
V8TestingScope scope;
auto* recorder = MakeGarbageCollected<MockMediaRecorder>(scope);
EXPECT_TRUE(media_recorder_handler_->Initialize(
recorder, registry_.test_stream(), "", "", 0, 0));
EXPECT_TRUE(media_recorder_handler_->Start(0));
// NOTE, Asan: the prototype of WriteData which has a const char* as data
// ptr plays badly with gmock which tries to interpret it as a null-terminated
// string. However, it points to binary data which causes gmock to overrun the
// bounds of buffers and this manifests as an ASAN crash.
// The expectation here works around this issue.
EXPECT_CALL(*recorder, WriteData).Times(AtLeast(1));
EXPECT_CALL(*recorder, OnError).WillOnce(Invoke([&](const String&) {
// Simulate MediaRecorder behavior which is to Stop() the handler on error.
media_recorder_handler_->Stop();
}));
OnVideoFrameForTesting(FakeEncodedVideoFrame::Builder()
.WithKeyFrame(true)
.WithCodec(media::kCodecVP8)
.WithData(std::string("vp8 frame"))
.BuildRefPtr());
// Switch to VP9 frames. This is expected to cause the call to OnError
// above.
OnVideoFrameForTesting(FakeEncodedVideoFrame::Builder()
.WithKeyFrame(true)
.WithCodec(media::kCodecVP9)
.WithData(std::string("vp9 frame"))
.BuildRefPtr());
// Send one more frame to verify that continued frame of different codec
// transfer doesn't crash the media recorder.
OnVideoFrameForTesting(FakeEncodedVideoFrame::Builder()
.WithKeyFrame(true)
.WithCodec(media::kCodecVP9)
.WithData(std::string("vp9 frame"))
.BuildRefPtr());
platform_->RunUntilIdle();
}
INSTANTIATE_TEST_SUITE_P(, INSTANTIATE_TEST_SUITE_P(,
MediaRecorderHandlerPassthroughTest, MediaRecorderHandlerPassthroughTest,
ValuesIn(kMediaRecorderPassthroughTestParams)); ValuesIn(kMediaRecorderPassthroughTestParams));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment