Commit 59f0d053 authored by Miguel Casas's avatar Miguel Casas Committed by Commit Bot

MediaRecorder: Retrieve actual recording mime type if not user-specified

This CL introduces a new  MediaRecorderHandler::ActualMimeType() method
that produces the mimeType used for recording by MRHandler. This method
is then called from Blink's MediaRecorder when the user has specified
no mime type for recording, so the output Blobs can have the correct
type.

Bug: 859199
Change-Id: I941f46a2ef495f5ac68995f79319fe6f07836a89
Reviewed-on: https://chromium-review.googlesource.com/1121141Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Reviewed-by: default avatarEmircan Uysaler <emircan@chromium.org>
Commit-Queue: Miguel Casas <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572207}
parent cc396e0d
...@@ -123,8 +123,8 @@ MediaRecorderHandler::MediaRecorderHandler( ...@@ -123,8 +123,8 @@ MediaRecorderHandler::MediaRecorderHandler(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: video_bits_per_second_(0), : video_bits_per_second_(0),
audio_bits_per_second_(0), audio_bits_per_second_(0),
video_codec_id_(VideoTrackRecorder::CodecId::VP8), video_codec_id_(VideoTrackRecorder::CodecId::LAST),
audio_codec_id_(AudioTrackRecorder::CodecId::OPUS), audio_codec_id_(AudioTrackRecorder::CodecId::LAST),
recording_(false), recording_(false),
client_(nullptr), client_(nullptr),
task_runner_(std::move(task_runner)), task_runner_(std::move(task_runner)),
...@@ -399,6 +399,72 @@ void MediaRecorderHandler::EncodingInfo( ...@@ -399,6 +399,72 @@ void MediaRecorderHandler::EncodingInfo(
scoped_callbacks.PassCallbacks()->OnSuccess(std::move(info)); scoped_callbacks.PassCallbacks()->OnSuccess(std::move(info));
} }
blink::WebString MediaRecorderHandler::ActualMimeType() {
DCHECK(main_render_thread_checker_.CalledOnValidThread());
DCHECK(client_) << __func__ << " should be called after Initialize()";
const bool has_video_tracks = !media_stream_.VideoTracks().empty();
const bool has_audio_tracks = !media_stream_.AudioTracks().empty();
if (!has_video_tracks && !has_audio_tracks)
return blink::WebString();
std::string mime_type;
if (!has_video_tracks && has_audio_tracks) {
mime_type.append("audio/webm;codecs=");
} else {
switch (video_codec_id_) {
case VideoTrackRecorder::CodecId::VP8:
case VideoTrackRecorder::CodecId::VP9:
mime_type.append("video/webm;codecs=");
break;
#if BUILDFLAG(RTC_USE_H264)
case VideoTrackRecorder::CodecId::H264:
mime_type.append("video/x-matroska;codecs=");
break;
#endif
case VideoTrackRecorder::CodecId::LAST:
// Do nothing.
break;
}
}
if (has_video_tracks) {
switch (video_codec_id_) {
case VideoTrackRecorder::CodecId::VP8:
mime_type.append("vp8");
break;
case VideoTrackRecorder::CodecId::VP9:
mime_type.append("vp9");
break;
#if BUILDFLAG(RTC_USE_H264)
case VideoTrackRecorder::CodecId::H264:
mime_type.append("avc1");
break;
#endif
case VideoTrackRecorder::CodecId::LAST:
DCHECK_NE(audio_codec_id_, AudioTrackRecorder::CodecId::LAST);
}
}
if (has_video_tracks && has_audio_tracks) {
if (video_codec_id_ != VideoTrackRecorder::CodecId::LAST &&
audio_codec_id_ != AudioTrackRecorder::CodecId::LAST) {
mime_type.append(",");
}
}
if (has_audio_tracks) {
switch (audio_codec_id_) {
case AudioTrackRecorder::CodecId::OPUS:
mime_type.append("opus");
break;
case AudioTrackRecorder::CodecId::PCM:
mime_type.append("pcm");
break;
case AudioTrackRecorder::CodecId::LAST:
DCHECK_NE(video_codec_id_, VideoTrackRecorder::CodecId::LAST);
}
}
return blink::WebString::FromUTF8(mime_type);
}
void MediaRecorderHandler::OnEncodedVideo( void MediaRecorderHandler::OnEncodedVideo(
const media::WebmMuxer::VideoParameters& params, const media::WebmMuxer::VideoParameters& params,
std::unique_ptr<std::string> encoded_data, std::unique_ptr<std::string> encoded_data,
......
...@@ -67,6 +67,7 @@ class CONTENT_EXPORT MediaRecorderHandler final ...@@ -67,6 +67,7 @@ class CONTENT_EXPORT MediaRecorderHandler final
void EncodingInfo( void EncodingInfo(
const blink::WebMediaConfiguration& configuration, const blink::WebMediaConfiguration& configuration,
std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks> cb) override; std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks> cb) override;
blink::WebString ActualMimeType() override;
private: private:
friend class MediaRecorderHandlerTest; friend class MediaRecorderHandlerTest;
......
...@@ -65,11 +65,12 @@ static const MediaRecorderTestParams kMediaRecorderTestParams[] = { ...@@ -65,11 +65,12 @@ static const MediaRecorderTestParams kMediaRecorderTestParams[] = {
{true, false, "video/webm", "vp8", true}, {true, false, "video/webm", "vp8", true},
{true, false, "video/webm", "vp9", true}, {true, false, "video/webm", "vp9", true},
#if BUILDFLAG(RTC_USE_H264) #if BUILDFLAG(RTC_USE_H264)
{true, false, "video/webm", "h264", false}, {true, false, "video/x-matroska", "avc1", false},
#endif #endif
{false, true, "audio/webm", "opus", true}, {false, true, "audio/webm", "opus", true},
{false, true, "audio/webm", "", true}, // Should default to opus. {false, true, "audio/webm", "", true}, // Should default to opus.
{false, true, "audio/webm", "pcm", true}, {false, true, "audio/webm", "pcm", true},
{true, true, "video/webm", "vp9,opus", true},
}; };
class MediaRecorderHandlerTest : public TestWithParam<MediaRecorderTestParams>, class MediaRecorderHandlerTest : public TestWithParam<MediaRecorderTestParams>,
...@@ -429,6 +430,29 @@ TEST_P(MediaRecorderHandlerTest, WebmMuxerErrorWhileEncoding) { ...@@ -429,6 +430,29 @@ TEST_P(MediaRecorderHandlerTest, WebmMuxerErrorWhileEncoding) {
run_loop.Run(); run_loop.Run();
} }
// Expect a last call on destruction, with size 0 and |lastInSlice| true.
EXPECT_CALL(*this, WriteData(nullptr, 0, true, _)).Times(1);
media_recorder_handler_.reset();
}
// Checks the ActualMimeType() versus the expected.
TEST_P(MediaRecorderHandlerTest, ActualMimeType) {
AddTracks();
const WebString mime_type(WebString::FromASCII(GetParam().mime_type));
const WebString codecs(WebString::FromASCII(GetParam().codecs));
EXPECT_TRUE(media_recorder_handler_->Initialize(this, registry_.test_stream(),
mime_type, codecs, 0, 0));
std::string actual_mime_type(GetParam().mime_type);
actual_mime_type.append(";codecs=");
if (strlen(GetParam().codecs) != 0u)
actual_mime_type.append(GetParam().codecs);
else if (GetParam().has_video)
actual_mime_type.append("vp8");
else if (GetParam().has_audio)
actual_mime_type.append("opus");
EXPECT_EQ(media_recorder_handler_->ActualMimeType().Utf8(), actual_mime_type);
// Expect a last call on destruction, with size 0 and |lastInSlice| true. // Expect a last call on destruction, with size 0 and |lastInSlice| true.
EXPECT_CALL(*this, WriteData(nullptr, 0, true, _)).Times(1); EXPECT_CALL(*this, WriteData(nullptr, 0, true, _)).Times(1);
......
...@@ -26,7 +26,7 @@ var makeAsyncTest = function(value, expected) { ...@@ -26,7 +26,7 @@ var makeAsyncTest = function(value, expected) {
async_test(function(test) { async_test(function(test) {
const recorderOnDataAvailable = test.step_func_done(function(event) { const recorderOnDataAvailable = test.step_func_done(function(event) {
assert_equals(event.data.size, 0, 'Recorded data size should be == 0'); assert_equals(event.data.size, 0, 'Recorded data size should be == 0');
assert_equals(event.data.type, "video/webm"); assert_equals(event.data.type, value['mimeType']);
assert_not_equals(event.timecode, NaN, 'timecode'); assert_not_equals(event.timecode, NaN, 'timecode');
}); });
...@@ -60,8 +60,11 @@ var makeAsyncTest = function(value, expected) { ...@@ -60,8 +60,11 @@ var makeAsyncTest = function(value, expected) {
}; };
generate_tests(makeAsyncTest, generate_tests(makeAsyncTest,
[["video-only", {video: true, audio: false}], [["video-only",
["audio-only", {video: false, audio: true}], {video: true, audio: false, mimeType: "video/webm;codecs=vp8"}],
["audio-video", {video: true, audio: true}]]); ["audio-only",
{video: false, audio: true, mimeType: "audio/webm;codecs=opus"}],
["audio-video",
{video: true, audio: true, mimeType: "video/webm;codecs=vp8,opus"}]]);
</script> </script>
...@@ -10,13 +10,13 @@ ...@@ -10,13 +10,13 @@
#include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_info.h" #include "third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_info.h"
#include "third_party/blink/public/platform/web_string.h"
namespace blink { namespace blink {
class WebMediaRecorderHandlerClient; class WebMediaRecorderHandlerClient;
struct WebMediaConfiguration; struct WebMediaConfiguration;
class WebMediaStream; class WebMediaStream;
class WebString;
// Platform interface of a MediaRecorder. // Platform interface of a MediaRecorder.
class BLINK_PLATFORM_EXPORT WebMediaRecorderHandler { class BLINK_PLATFORM_EXPORT WebMediaRecorderHandler {
...@@ -47,6 +47,9 @@ class BLINK_PLATFORM_EXPORT WebMediaRecorderHandler { ...@@ -47,6 +47,9 @@ class BLINK_PLATFORM_EXPORT WebMediaRecorderHandler {
return false; return false;
} }
// What is really being encoded???
virtual WebString ActualMimeType() { return WebString(); }
// Implements WICG Media Capabilities encodingInfo() call for local encoding. // Implements WICG Media Capabilities encodingInfo() call for local encoding.
// https://wicg.github.io/media-capabilities/#media-capabilities-interface // https://wicg.github.io/media-capabilities/#media-capabilities-interface
virtual void EncodingInfo( virtual void EncodingInfo(
......
...@@ -202,6 +202,12 @@ MediaRecorder::MediaRecorder(ExecutionContext* context, ...@@ -202,6 +202,12 @@ MediaRecorder::MediaRecorder(ExecutionContext* context,
mime_type_ + ") is not supported."); mime_type_ + ") is not supported.");
return; return;
} }
// If the user requested no mimeType, query |recorder_handler_|.
if (options.mimeType().IsEmpty()) {
const String actual_mime_type = recorder_handler_->ActualMimeType();
if (!actual_mime_type.IsEmpty())
mime_type_ = actual_mime_type;
}
stopped_ = false; stopped_ = false;
} }
......
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