| Index: content/renderer/media/media_recorder_handler.cc
|
| diff --git a/content/renderer/media/media_recorder_handler.cc b/content/renderer/media/media_recorder_handler.cc
|
| index 7144af2f865b0577a58babb90cc7de40aead7b19..c260407494ac9455a5c2b8c3a51158c3e1a0574c 100644
|
| --- a/content/renderer/media/media_recorder_handler.cc
|
| +++ b/content/renderer/media/media_recorder_handler.cc
|
| @@ -7,8 +7,13 @@
|
| #include "base/bind.h"
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| +#include "base/strings/string_tokenizer.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "content/renderer/media/audio_track_recorder.h"
|
| #include "content/renderer/media/video_track_recorder.h"
|
| #include "content/renderer/media/webrtc_uma_histograms.h"
|
| +#include "media/audio/audio_parameters.h"
|
| +#include "media/base/audio_bus.h"
|
| #include "media/base/bind_to_current_loop.h"
|
| #include "media/base/video_frame.h"
|
| #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h"
|
| @@ -27,9 +32,7 @@ MediaRecorderHandler::MediaRecorderHandler()
|
| : use_vp9_(false),
|
| recording_(false),
|
| client_(nullptr),
|
| - weak_factory_(this) {
|
| - DVLOG(3) << __FUNCTION__;
|
| -}
|
| + weak_factory_(this) {}
|
|
|
| MediaRecorderHandler::~MediaRecorderHandler() {
|
| DCHECK(main_render_thread_checker_.CalledOnValidThread());
|
| @@ -41,9 +44,24 @@ MediaRecorderHandler::~MediaRecorderHandler() {
|
| bool MediaRecorderHandler::canSupportMimeType(
|
| const blink::WebString& mimeType) {
|
| DCHECK(main_render_thread_checker_.CalledOnValidThread());
|
| - // TODO(mcasas): So far only empty or "video/vp{8,9}" are supported.
|
| - return mimeType.isEmpty() || mimeType.utf8().compare("video/vp8") == 0 ||
|
| - mimeType.utf8().compare("video/vp9") == 0;
|
| + // Ensure we can support each passed MIME type.
|
| + const std::string input = mimeType.utf8(); // Must outlive tokenizer!
|
| + base::StringTokenizer tokenizer(input, ",");
|
| + while (tokenizer.GetNext()) {
|
| + // Strip whitespace.
|
| + const std::string token(base::CollapseWhitespaceASCII(
|
| + tokenizer.token(), true /* trim sequences with line breaks*/));
|
| + if (!token.empty() &&
|
| + !base::EqualsCaseInsensitiveASCII(token, "video/vp8") &&
|
| + !base::EqualsCaseInsensitiveASCII(token, "video/vp9") &&
|
| + !base::EqualsCaseInsensitiveASCII(token, "audio/opus") &&
|
| + !base::EqualsCaseInsensitiveASCII(token, "video/webm") &&
|
| + !base::EqualsCaseInsensitiveASCII(token, "audio/webm")) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + return true;
|
| }
|
|
|
| bool MediaRecorderHandler::initialize(
|
| @@ -82,44 +100,63 @@ bool MediaRecorderHandler::start(int timeslice) {
|
| timeslice_ = TimeDelta::FromMilliseconds(timeslice);
|
| slice_origin_timestamp_ = TimeTicks::Now();
|
|
|
| - blink::WebVector<blink::WebMediaStreamTrack> video_tracks;
|
| + blink::WebVector<blink::WebMediaStreamTrack> video_tracks, audio_tracks;
|
| media_stream_.videoTracks(video_tracks);
|
| + media_stream_.audioTracks(audio_tracks);
|
|
|
| -#if !defined(MEDIA_DISABLE_LIBWEBM)
|
| - DCHECK(!webm_muxer_);
|
| -
|
| - webm_muxer_.reset(new media::WebmMuxer(
|
| - use_vp9_ ? media::kCodecVP9 : media::kCodecVP8, video_tracks.size() > 0,
|
| - false /* no audio for now - http://crbug.com/528519 */,
|
| - base::Bind(&MediaRecorderHandler::WriteData,
|
| - weak_factory_.GetWeakPtr())));
|
| -#else
|
| +#if defined(MEDIA_DISABLE_LIBWEBM)
|
| LOG(WARNING) << "No muxer available";
|
| return false;
|
| #endif
|
|
|
| - if (video_tracks.isEmpty()) {
|
| - // TODO(mcasas): Add audio_tracks and update the code in this function
|
| - // correspondingly, see http://crbug.com/528519. As of now, only video
|
| - // tracks are supported.
|
| - LOG(WARNING) << "Recording no video tracks is not implemented";
|
| + DCHECK(!webm_muxer_);
|
| +
|
| + if (video_tracks.isEmpty() && audio_tracks.isEmpty()) {
|
| + LOG(WARNING) << __FUNCTION__ << ": no media tracks.";
|
| return false;
|
| }
|
| - // TODO(mcasas): The muxer API supports only one video track. Extend it to
|
| - // several video tracks, see http://crbug.com/528523.
|
| - LOG_IF(WARNING, video_tracks.size() > 1u) << "Recording multiple video"
|
| - << " tracks is not implemented. Only recording first video track.";
|
| - const blink::WebMediaStreamTrack& video_track = video_tracks[0];
|
| - if (video_track.isNull())
|
| - return false;
|
|
|
| - const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_cb =
|
| - media::BindToCurrentLoop(base::Bind(&MediaRecorderHandler::OnEncodedVideo,
|
| - weak_factory_.GetWeakPtr()));
|
| + webm_muxer_.reset(new media::WebmMuxer(
|
| + use_vp9_ ? media::kCodecVP9 : media::kCodecVP8,
|
| + video_tracks.size() > 0, audio_tracks.size() > 0,
|
| + base::Bind(&MediaRecorderHandler::WriteData,
|
| + weak_factory_.GetWeakPtr())));
|
|
|
| - video_recorders_.push_back(new VideoTrackRecorder(use_vp9_,
|
| - video_track,
|
| - on_encoded_video_cb));
|
| + if (!video_tracks.isEmpty()) {
|
| + // TODO(mcasas): The muxer API supports only one video track. Extend it to
|
| + // several video tracks, see http://crbug.com/528523.
|
| + LOG_IF(WARNING, video_tracks.size() > 1u)
|
| + << "Recording multiple video tracks is not implemented. "
|
| + << "Only recording first video track.";
|
| + const blink::WebMediaStreamTrack& video_track = video_tracks[0];
|
| + if (video_track.isNull())
|
| + return false;
|
| +
|
| + const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_cb =
|
| + media::BindToCurrentLoop(base::Bind(
|
| + &MediaRecorderHandler::OnEncodedVideo, weak_factory_.GetWeakPtr()));
|
| +
|
| + video_recorders_.push_back(
|
| + new VideoTrackRecorder(use_vp9_, video_track, on_encoded_video_cb));
|
| + }
|
| +
|
| + if (!audio_tracks.isEmpty()) {
|
| + // TODO(ajose): The muxer API supports only one audio track. Extend it to
|
| + // several tracks.
|
| + LOG_IF(WARNING, audio_tracks.size() > 1u)
|
| + << "Recording multiple audio"
|
| + << " tracks is not implemented. Only recording first audio track.";
|
| + const blink::WebMediaStreamTrack& audio_track = audio_tracks[0];
|
| + if (audio_track.isNull())
|
| + return false;
|
| +
|
| + const AudioTrackRecorder::OnEncodedAudioCB on_encoded_audio_cb =
|
| + media::BindToCurrentLoop(base::Bind(
|
| + &MediaRecorderHandler::OnEncodedAudio, weak_factory_.GetWeakPtr()));
|
| +
|
| + audio_recorders_.push_back(
|
| + new AudioTrackRecorder(audio_track, on_encoded_audio_cb));
|
| + }
|
|
|
| recording_ = true;
|
| return true;
|
| @@ -132,6 +169,7 @@ void MediaRecorderHandler::stop() {
|
| recording_ = false;
|
| timeslice_ = TimeDelta::FromMilliseconds(0);
|
| video_recorders_.clear();
|
| + audio_recorders_.clear();
|
| #if !defined(MEDIA_DISABLE_LIBWEBM)
|
| webm_muxer_.reset();
|
| #endif
|
| @@ -167,6 +205,14 @@ void MediaRecorderHandler::OnEncodedVideo(
|
| #endif
|
| }
|
|
|
| +void MediaRecorderHandler::OnEncodedAudio(const media::AudioParameters& params,
|
| + scoped_ptr<std::string> encoded_data,
|
| + base::TimeTicks timestamp) {
|
| + DCHECK(main_render_thread_checker_.CalledOnValidThread());
|
| + if (webm_muxer_)
|
| + webm_muxer_->OnEncodedAudio(params, encoded_data.Pass(), timestamp);
|
| +}
|
| +
|
| void MediaRecorderHandler::WriteData(base::StringPiece data) {
|
| DCHECK(main_render_thread_checker_.CalledOnValidThread());
|
|
|
| @@ -191,4 +237,17 @@ void MediaRecorderHandler::OnVideoFrameForTesting(
|
| recorder->OnVideoFrameForTesting(frame, timestamp);
|
| }
|
|
|
| +void MediaRecorderHandler::OnAudioBusForTesting(
|
| + const media::AudioBus& audio_bus,
|
| + const base::TimeTicks& timestamp) {
|
| + for (auto* recorder : audio_recorders_)
|
| + recorder->OnData(audio_bus, timestamp);
|
| +}
|
| +
|
| +void MediaRecorderHandler::SetAudioFormatForTesting(
|
| + const media::AudioParameters& params) {
|
| + for (auto* recorder : audio_recorders_)
|
| + recorder->OnSetFormat(params);
|
| +}
|
| +
|
| } // namespace content
|
|
|