Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: content/renderer/media/media_recorder_handler.cc

Issue 2234563002: MediaRecorder: support recording with no multiplexing (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: consider empty mimeTypes Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/media_recorder_handler.h" 5 #include "content/renderer/media/media_recorder_handler.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 29 matching lines...) Expand all
40 return media::kCodecVP8; 40 return media::kCodecVP8;
41 case VideoTrackRecorder::CodecId::VP9: 41 case VideoTrackRecorder::CodecId::VP9:
42 return media::kCodecVP9; 42 return media::kCodecVP9;
43 case VideoTrackRecorder::CodecId::H264: 43 case VideoTrackRecorder::CodecId::H264:
44 return media::kCodecH264; 44 return media::kCodecH264;
45 } 45 }
46 NOTREACHED() << "Unsupported codec"; 46 NOTREACHED() << "Unsupported codec";
47 return media::kUnknownVideoCodec; 47 return media::kUnknownVideoCodec;
48 } 48 }
49 49
50 // Extracts the MIME subtype from an incoming |content_type|, or empty.
51 std::string getSubtypeFromContentType(const std::string& content_type) {
52 base::StringTokenizer web_type_tokens(content_type, "/");
53 if (!web_type_tokens.GetNext() || !web_type_tokens.GetNext())
54 return std::string();
55 return web_type_tokens.token();
56 }
57
58 bool findCodecInList(const std::string& codec,
59 const char* const* codecs,
60 size_t codecs_count) {
61 auto* const* found = std::find_if(
62 &codecs[0], &codecs[codecs_count], [&codec](const char* name) {
63 return base::EqualsCaseInsensitiveASCII(codec, name);
64 });
65 return found != &codecs[codecs_count];
66 }
67
50 } // anonymous namespace 68 } // anonymous namespace
51 69
52 MediaRecorderHandler::MediaRecorderHandler() 70 MediaRecorderHandler::MediaRecorderHandler()
53 : video_bits_per_second_(0), 71 : video_bits_per_second_(0),
54 audio_bits_per_second_(0), 72 audio_bits_per_second_(0),
73 use_container_(true),
55 codec_id_(VideoTrackRecorder::CodecId::VP8), 74 codec_id_(VideoTrackRecorder::CodecId::VP8),
56 recording_(false), 75 recording_(false),
57 client_(nullptr), 76 client_(nullptr),
58 weak_factory_(this) {} 77 weak_factory_(this) {}
59 78
60 MediaRecorderHandler::~MediaRecorderHandler() { 79 MediaRecorderHandler::~MediaRecorderHandler() {
61 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 80 DCHECK(main_render_thread_checker_.CalledOnValidThread());
62 // Send a |last_in_slice| to our |client_|. 81 // Send a |last_in_slice| to our |client_|.
63 if (client_) 82 if (client_)
64 client_->writeData(nullptr, 0u, true); 83 client_->writeData(nullptr, 0u, true);
65 } 84 }
66 85
67 bool MediaRecorderHandler::canSupportMimeType( 86 bool MediaRecorderHandler::canSupportMimeType(
68 const blink::WebString& web_type, 87 const blink::WebString& web_type,
69 const blink::WebString& web_codecs) { 88 const blink::WebString& web_codecs) {
70 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 89 DCHECK(main_render_thread_checker_.CalledOnValidThread());
71 // An empty |web_type| means MediaRecorderHandler can choose its preferred 90 // An empty |web_type| means MediaRecorderHandler can choose its preferred
72 // codecs. 91 // codecs.
73 if (web_type.isEmpty()) 92 if (web_type.isEmpty())
74 return true; 93 return true;
75 94
76 const std::string type(web_type.utf8()); 95 const std::string type(web_type.utf8());
77 const bool video = base::EqualsCaseInsensitiveASCII(type, "video/webm"); 96 const bool video =
97 base::StartsWith(type, "video/", base::CompareCase::INSENSITIVE_ASCII);
78 const bool audio = 98 const bool audio =
79 video ? false : base::EqualsCaseInsensitiveASCII(type, "audio/webm"); 99 video ? false : base::StartsWith(type, "audio/",
100 base::CompareCase::INSENSITIVE_ASCII);
80 if (!video && !audio) 101 if (!video && !audio)
81 return false; 102 return false;
82 103
83 // Both |video| and |audio| support empty |codecs|; |type| == "video" supports 104 // Both |video| and |audio| support empty |codecs|; |type| == "video" supports
84 // vp8, vp9 or opus; |type| = "audio", supports only opus. 105 // vp8, vp9, H264 or opus; |type| = "audio", supports only opus.
85 // http://www.webmproject.org/docs/container Sec:"HTML5 Video Type Parameters" 106 // http://www.webmproject.org/docs/container Sec:"HTML5 Video Type Parameters"
86 static const char* const kVideoCodecs[] = { "vp8", "vp9", "h264", "opus" }; 107 static const char* const kVideoCodecs[] = { "vp8", "vp9", "h264", "opus" };
87 static const char* const kAudioCodecs[] = { "opus" }; 108 static const char* const kAudioCodecs[] = { "opus" };
88 const char* const* codecs = video ? &kVideoCodecs[0] : &kAudioCodecs[0]; 109 const char* const* codecs = video ? &kVideoCodecs[0] : &kAudioCodecs[0];
89 const int codecs_count = 110 const int codecs_count =
90 video ? arraysize(kVideoCodecs) : arraysize(kAudioCodecs); 111 video ? arraysize(kVideoCodecs) : arraysize(kAudioCodecs);
91 112
113 // Check for the container or the codec following video/ or audio/. "webm"
114 // container is supported,; so are any of the |codecs| as non-contained.
115 const std::string mime_subtype = getSubtypeFromContentType(type);
116 if (!base::EqualsCaseInsensitiveASCII(mime_subtype, "webm"))
117 return findCodecInList(mime_subtype, codecs, codecs_count);
118
92 std::vector<std::string> codecs_list; 119 std::vector<std::string> codecs_list;
93 media::ParseCodecString(web_codecs.utf8(), &codecs_list, true /* strip */); 120 media::ParseCodecString(web_codecs.utf8(), &codecs_list, true /* strip */);
94 for (const auto& codec : codecs_list) { 121 for (const auto& codec : codecs_list) {
95 auto* const* found = std::find_if( 122 if (!findCodecInList(codec, codecs, codecs_count))
96 &codecs[0], &codecs[codecs_count], [&codec](const char* name) {
97 return base::EqualsCaseInsensitiveASCII(codec, name);
98 });
99 if (found == &codecs[codecs_count])
100 return false; 123 return false;
101 } 124 }
102 return true; 125 return true;
103 } 126 }
104 127
105 bool MediaRecorderHandler::initialize( 128 bool MediaRecorderHandler::initialize(
106 blink::WebMediaRecorderHandlerClient* client, 129 blink::WebMediaRecorderHandlerClient* client,
107 const blink::WebMediaStream& media_stream, 130 const blink::WebMediaStream& media_stream,
108 const blink::WebString& type, 131 const blink::WebString& type,
109 const blink::WebString& codecs, 132 const blink::WebString& codecs,
110 int32_t audio_bits_per_second, 133 int32_t audio_bits_per_second,
111 int32_t video_bits_per_second) { 134 int32_t video_bits_per_second) {
112 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 135 DCHECK(main_render_thread_checker_.CalledOnValidThread());
113 // Save histogram data so we can see how much MediaStream Recorder is used. 136 // Save histogram data so we can see how much MediaStream Recorder is used.
114 // The histogram counts the number of calls to the JS API. 137 // The histogram counts the number of calls to the JS API.
115 UpdateWebRTCMethodCount(WEBKIT_MEDIA_STREAM_RECORDER); 138 UpdateWebRTCMethodCount(WEBKIT_MEDIA_STREAM_RECORDER);
116 139
117 if (!canSupportMimeType(type, codecs)) { 140 if (!canSupportMimeType(type, codecs)) {
118 DLOG(ERROR) << "Can't support " << type.utf8() 141 DLOG(ERROR) << "Can't support " << type.utf8()
119 << ";codecs=" << codecs.utf8(); 142 << ";codecs=" << codecs.utf8();
120 return false; 143 return false;
121 } 144 }
122 145
146 const std::string mime_subtype = getSubtypeFromContentType(type.utf8());
147 use_container_ =
148 type.isEmpty() || base::EqualsCaseInsensitiveASCII(mime_subtype, "webm");
149
150 const std::string& codecs_str =
151 use_container_ ? ToLowerASCII(codecs.utf8()) : ToLowerASCII(mime_subtype);
152
123 // Once established that we support the codec(s), hunt then individually. 153 // Once established that we support the codec(s), hunt then individually.
124 const std::string& codecs_str = ToLowerASCII(codecs.utf8());
125 if (codecs_str.find("vp8") != std::string::npos) 154 if (codecs_str.find("vp8") != std::string::npos)
126 codec_id_ = VideoTrackRecorder::CodecId::VP8; 155 codec_id_ = VideoTrackRecorder::CodecId::VP8;
127 else if (codecs_str.find("vp9") != std::string::npos) 156 else if (codecs_str.find("vp9") != std::string::npos)
128 codec_id_ = VideoTrackRecorder::CodecId::VP9; 157 codec_id_ = VideoTrackRecorder::CodecId::VP9;
129 #if BUILDFLAG(RTC_USE_H264) 158 #if BUILDFLAG(RTC_USE_H264)
130 else if (codecs_str.find("h264") != std::string::npos) 159 else if (codecs_str.find("h264") != std::string::npos)
131 codec_id_ = VideoTrackRecorder::CodecId::H264; 160 codec_id_ = VideoTrackRecorder::CodecId::H264;
132 #endif 161 #endif
133 162
134 media_stream_ = media_stream; 163 media_stream_ = media_stream;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 !audio_tracks.isEmpty() && MediaStreamAudioTrack::From(audio_tracks[0]) && 202 !audio_tracks.isEmpty() && MediaStreamAudioTrack::From(audio_tracks[0]) &&
174 audio_tracks[0].isEnabled() && 203 audio_tracks[0].isEnabled() &&
175 audio_tracks[0].source().getReadyState() != 204 audio_tracks[0].source().getReadyState() !=
176 blink::WebMediaStreamSource::ReadyStateEnded; 205 blink::WebMediaStreamSource::ReadyStateEnded;
177 206
178 if (!use_video_tracks && !use_audio_tracks) { 207 if (!use_video_tracks && !use_audio_tracks) {
179 LOG(WARNING) << __func__ << ": no tracks to be recorded."; 208 LOG(WARNING) << __func__ << ": no tracks to be recorded.";
180 return false; 209 return false;
181 } 210 }
182 211
183 webm_muxer_.reset(new media::WebmMuxer( 212 if (use_container_) {
184 CodecIdToMediaVideoCodec(codec_id_), use_video_tracks, use_audio_tracks, 213 webm_muxer_.reset(new media::WebmMuxer(
185 base::Bind(&MediaRecorderHandler::WriteData, 214 CodecIdToMediaVideoCodec(codec_id_), use_video_tracks, use_audio_tracks,
186 weak_factory_.GetWeakPtr()))); 215 base::Bind(&MediaRecorderHandler::WriteData,
216 weak_factory_.GetWeakPtr())));
217 }
187 218
188 if (use_video_tracks) { 219 if (use_video_tracks) {
189 // TODO(mcasas): The muxer API supports only one video track. Extend it to 220 // TODO(mcasas): The muxer API supports only one video track. Extend it to
190 // several video tracks, see http://crbug.com/528523. 221 // several video tracks, see http://crbug.com/528523.
191 LOG_IF(WARNING, video_tracks.size() > 1u) 222 LOG_IF(WARNING, video_tracks.size() > 1u)
192 << "Recording multiple video tracks is not implemented. " 223 << "Recording multiple video tracks is not implemented. "
193 << "Only recording first video track."; 224 << "Only recording first video track.";
194 const blink::WebMediaStreamTrack& video_track = video_tracks[0]; 225 const blink::WebMediaStreamTrack& video_track = video_tracks[0];
195 if (video_track.isNull()) 226 if (video_track.isNull())
196 return false; 227 return false;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 } 268 }
238 269
239 void MediaRecorderHandler::pause() { 270 void MediaRecorderHandler::pause() {
240 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 271 DCHECK(main_render_thread_checker_.CalledOnValidThread());
241 DCHECK(recording_); 272 DCHECK(recording_);
242 recording_ = false; 273 recording_ = false;
243 for (auto* video_recorder : video_recorders_) 274 for (auto* video_recorder : video_recorders_)
244 video_recorder->Pause(); 275 video_recorder->Pause();
245 for (auto* audio_recorder : audio_recorders_) 276 for (auto* audio_recorder : audio_recorders_)
246 audio_recorder->Pause(); 277 audio_recorder->Pause();
247 webm_muxer_->Pause(); 278 if (webm_muxer_)
279 webm_muxer_->Pause();
248 } 280 }
249 281
250 void MediaRecorderHandler::resume() { 282 void MediaRecorderHandler::resume() {
251 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 283 DCHECK(main_render_thread_checker_.CalledOnValidThread());
252 DCHECK(!recording_); 284 DCHECK(!recording_);
253 recording_ = true; 285 recording_ = true;
254 for (auto* video_recorder : video_recorders_) 286 for (auto* video_recorder : video_recorders_)
255 video_recorder->Resume(); 287 video_recorder->Resume();
256 for (auto* audio_recorder : audio_recorders_) 288 for (auto* audio_recorder : audio_recorders_)
257 audio_recorder->Resume(); 289 audio_recorder->Resume();
258 webm_muxer_->Resume(); 290 if (webm_muxer_)
291 webm_muxer_->Resume();
259 } 292 }
260 293
261 void MediaRecorderHandler::OnEncodedVideo( 294 void MediaRecorderHandler::OnEncodedVideo(
262 const scoped_refptr<media::VideoFrame>& video_frame, 295 const scoped_refptr<media::VideoFrame>& video_frame,
263 std::unique_ptr<std::string> encoded_data, 296 std::unique_ptr<std::string> encoded_data,
264 TimeTicks timestamp, 297 TimeTicks timestamp,
265 bool is_key_frame) { 298 bool is_key_frame) {
266 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 299 DCHECK(main_render_thread_checker_.CalledOnValidThread());
267 if (!webm_muxer_) 300 if (webm_muxer_) {
268 return; 301 return webm_muxer_->OnEncodedVideo(video_frame, std::move(encoded_data),
269 webm_muxer_->OnEncodedVideo(video_frame, std::move(encoded_data), timestamp, 302 timestamp, is_key_frame);
270 is_key_frame); 303 }
304 DCHECK(!use_container_);
305 WriteData(base::StringPiece(*encoded_data.get()));
271 } 306 }
272 307
273 void MediaRecorderHandler::OnEncodedAudio( 308 void MediaRecorderHandler::OnEncodedAudio(
274 const media::AudioParameters& params, 309 const media::AudioParameters& params,
275 std::unique_ptr<std::string> encoded_data, 310 std::unique_ptr<std::string> encoded_data,
276 base::TimeTicks timestamp) { 311 base::TimeTicks timestamp) {
277 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 312 DCHECK(main_render_thread_checker_.CalledOnValidThread());
278 if (webm_muxer_) 313 if (webm_muxer_)
279 webm_muxer_->OnEncodedAudio(params, std::move(encoded_data), timestamp); 314 webm_muxer_->OnEncodedAudio(params, std::move(encoded_data), timestamp);
280 } 315 }
(...skipping 28 matching lines...) Expand all
309 recorder->OnData(audio_bus, timestamp); 344 recorder->OnData(audio_bus, timestamp);
310 } 345 }
311 346
312 void MediaRecorderHandler::SetAudioFormatForTesting( 347 void MediaRecorderHandler::SetAudioFormatForTesting(
313 const media::AudioParameters& params) { 348 const media::AudioParameters& params) {
314 for (auto* recorder : audio_recorders_) 349 for (auto* recorder : audio_recorders_)
315 recorder->OnSetFormat(params); 350 recorder->OnSetFormat(params);
316 } 351 }
317 352
318 } // namespace content 353 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698