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

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

Issue 1920483002: MediaRecorderHandler and WebmMuxer: add support for H264. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed TODO (V_MPEG4/ISO/AVC) and adapted unit tests Created 4 years, 7 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"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/strings/string_tokenizer.h" 13 #include "base/strings/string_tokenizer.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "content/renderer/media/audio_track_recorder.h" 15 #include "content/renderer/media/audio_track_recorder.h"
16 #include "content/renderer/media/media_stream_audio_track.h" 16 #include "content/renderer/media/media_stream_audio_track.h"
17 #include "content/renderer/media/media_stream_track.h" 17 #include "content/renderer/media/media_stream_track.h"
18 #include "content/renderer/media/video_track_recorder.h"
19 #include "content/renderer/media/webrtc_uma_histograms.h" 18 #include "content/renderer/media/webrtc_uma_histograms.h"
20 #include "media/base/audio_bus.h" 19 #include "media/base/audio_bus.h"
21 #include "media/base/audio_parameters.h" 20 #include "media/base/audio_parameters.h"
22 #include "media/base/bind_to_current_loop.h" 21 #include "media/base/bind_to_current_loop.h"
23 #include "media/base/mime_util.h" 22 #include "media/base/mime_util.h"
24 #include "media/base/video_frame.h" 23 #include "media/base/video_frame.h"
25 #include "media/muxers/webm_muxer.h" 24 #include "media/muxers/webm_muxer.h"
26 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" 25 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h"
27 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 26 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
28 #include "third_party/WebKit/public/platform/WebString.h" 27 #include "third_party/WebKit/public/platform/WebString.h"
29 28
30 using base::TimeDelta; 29 using base::TimeDelta;
31 using base::TimeTicks; 30 using base::TimeTicks;
31 using base::ToLowerASCII;
32 32
33 namespace content { 33 namespace content {
34 34
35 namespace {
36
37 media::VideoCodec CodecIdToMediaVideoCodec(VideoTrackRecorder::CodecId id) {
38 switch (id) {
39 case VideoTrackRecorder::CodecId::VP8:
40 return media::kCodecVP8;
41 case VideoTrackRecorder::CodecId::VP9:
42 return media::kCodecVP8;
43 #if BUILDFLAG(RTC_USE_H264)
44 case VideoTrackRecorder::CodecId::H264:
45 return media::kCodecH264;
46 #endif
47 }
48 NOTREACHED() << "Unsupported codec";
49 return media::kUnknownVideoCodec;
50 }
51
52 } // anonymous namespace
53
35 MediaRecorderHandler::MediaRecorderHandler() 54 MediaRecorderHandler::MediaRecorderHandler()
36 : video_bits_per_second_(0), 55 : video_bits_per_second_(0),
37 audio_bits_per_second_(0), 56 audio_bits_per_second_(0),
38 use_vp9_(false), 57 codec_id_(VideoTrackRecorder::CodecId::VP8),
39 recording_(false), 58 recording_(false),
40 client_(nullptr), 59 client_(nullptr),
41 weak_factory_(this) {} 60 weak_factory_(this) {}
42 61
43 MediaRecorderHandler::~MediaRecorderHandler() { 62 MediaRecorderHandler::~MediaRecorderHandler() {
44 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 63 DCHECK(main_render_thread_checker_.CalledOnValidThread());
45 // Send a |last_in_slice| to our |client_|. 64 // Send a |last_in_slice| to our |client_|.
46 if (client_) 65 if (client_)
47 client_->writeData(nullptr, 0u, true); 66 client_->writeData(nullptr, 0u, true);
48 } 67 }
49 68
50 bool MediaRecorderHandler::canSupportMimeType( 69 bool MediaRecorderHandler::canSupportMimeType(
51 const blink::WebString& web_type, const blink::WebString& web_codecs) { 70 const blink::WebString& web_type,
71 const blink::WebString& web_codecs) {
52 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 72 DCHECK(main_render_thread_checker_.CalledOnValidThread());
53 // An empty |web_type| means MediaRecorderHandler can choose its preferred 73 // An empty |web_type| means MediaRecorderHandler can choose its preferred
54 // codecs. 74 // codecs.
55 if (web_type.isEmpty()) 75 if (web_type.isEmpty())
56 return true; 76 return true;
57 77
58 const std::string type(web_type.utf8()); 78 const std::string type(web_type.utf8());
59 const bool video = base::EqualsCaseInsensitiveASCII(type, "video/webm"); 79 const bool video = base::EqualsCaseInsensitiveASCII(type, "video/webm");
60 const bool audio = 80 const bool audio =
61 video ? false : base::EqualsCaseInsensitiveASCII(type, "audio/webm"); 81 video ? false : base::EqualsCaseInsensitiveASCII(type, "audio/webm");
62 if (!video && !audio) 82 if (!video && !audio)
63 return false; 83 return false;
64 84
65 // Both |video| and |audio| support empty |codecs|; |type| == "video" supports 85 // Both |video| and |audio| support empty |codecs|; |type| == "video" supports
66 // vp8, vp9 or opus; |type| = "audio", supports only opus. 86 // vp8, vp9 or opus; |type| = "audio", supports only opus.
67 // http://www.webmproject.org/docs/container Sec:"HTML5 Video Type Parameters" 87 // http://www.webmproject.org/docs/container Sec:"HTML5 Video Type Parameters"
68 static const char* const kVideoCodecs[] = { "vp8", "vp9", "opus" }; 88 static const char* const kVideoCodecs[] = { "vp8", "vp9", "h264", "opus" };
69 static const char* const kAudioCodecs[] = { "opus" }; 89 static const char* const kAudioCodecs[] = { "opus" };
70 const char* const* codecs = video ? &kVideoCodecs[0] : &kAudioCodecs[0]; 90 const char* const* codecs = video ? &kVideoCodecs[0] : &kAudioCodecs[0];
71 const int codecs_count = 91 const int codecs_count =
72 video ? arraysize(kVideoCodecs) : arraysize(kAudioCodecs); 92 video ? arraysize(kVideoCodecs) : arraysize(kAudioCodecs);
73 93
74 std::vector<std::string> codecs_list; 94 std::vector<std::string> codecs_list;
75 media::ParseCodecString(web_codecs.utf8(), &codecs_list, true /* strip */); 95 media::ParseCodecString(web_codecs.utf8(), &codecs_list, true /* strip */);
76 for (const auto& codec : codecs_list) { 96 for (const auto& codec : codecs_list) {
77 const auto found = std::find_if( 97 const auto found = std::find_if(
78 &codecs[0], &codecs[codecs_count], [&codec](const char* name) { 98 &codecs[0], &codecs[codecs_count], [&codec](const char* name) {
(...skipping 15 matching lines...) Expand all
94 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 114 DCHECK(main_render_thread_checker_.CalledOnValidThread());
95 // Save histogram data so we can see how much MediaStream Recorder is used. 115 // Save histogram data so we can see how much MediaStream Recorder is used.
96 // The histogram counts the number of calls to the JS API. 116 // The histogram counts the number of calls to the JS API.
97 UpdateWebRTCMethodCount(WEBKIT_MEDIA_STREAM_RECORDER); 117 UpdateWebRTCMethodCount(WEBKIT_MEDIA_STREAM_RECORDER);
98 118
99 if (!canSupportMimeType(type, codecs)) { 119 if (!canSupportMimeType(type, codecs)) {
100 DLOG(ERROR) << "Can't support " << type.utf8() 120 DLOG(ERROR) << "Can't support " << type.utf8()
101 << ";codecs=" << codecs.utf8(); 121 << ";codecs=" << codecs.utf8();
102 return false; 122 return false;
103 } 123 }
104 use_vp9_ = base::ToLowerASCII(codecs.utf8()).find("vp9") != std::string::npos; 124
125 // Once established that we support the codec(s), hunt then individually.
126 const std::string& codecs_str = ToLowerASCII(codecs.utf8());
127 if (codecs_str.find("vp8") != std::string::npos)
128 codec_id_ = VideoTrackRecorder::CodecId::VP8;
129 else if (codecs_str.find("vp9") != std::string::npos)
130 codec_id_ = VideoTrackRecorder::CodecId::VP9;
131 #if BUILDFLAG(RTC_USE_H264)
132 else if (codecs_str.find("h264") != std::string::npos)
133 codec_id_ = VideoTrackRecorder::CodecId::H264;
134 #endif
135
105 media_stream_ = media_stream; 136 media_stream_ = media_stream;
106 DCHECK(client); 137 DCHECK(client);
107 client_ = client; 138 client_ = client;
108 139
109 audio_bits_per_second_ = audio_bits_per_second; 140 audio_bits_per_second_ = audio_bits_per_second;
110 video_bits_per_second_ = video_bits_per_second; 141 video_bits_per_second_ = video_bits_per_second;
111 return true; 142 return true;
112 } 143 }
113 144
114 bool MediaRecorderHandler::start() { 145 bool MediaRecorderHandler::start() {
(...skipping 25 matching lines...) Expand all
140 video_tracks[0].isEnabled() && 171 video_tracks[0].isEnabled() &&
141 video_tracks[0].source().getReadyState() == 172 video_tracks[0].source().getReadyState() ==
142 blink::WebMediaStreamSource::ReadyStateLive; 173 blink::WebMediaStreamSource::ReadyStateLive;
143 const bool use_audio_tracks = !audio_tracks.isEmpty() && 174 const bool use_audio_tracks = !audio_tracks.isEmpty() &&
144 MediaStreamAudioTrack::From(audio_tracks[0]) && 175 MediaStreamAudioTrack::From(audio_tracks[0]) &&
145 audio_tracks[0].isEnabled() && 176 audio_tracks[0].isEnabled() &&
146 audio_tracks[0].source().getReadyState() == 177 audio_tracks[0].source().getReadyState() ==
147 blink::WebMediaStreamSource::ReadyStateLive; 178 blink::WebMediaStreamSource::ReadyStateLive;
148 179
149 webm_muxer_.reset(new media::WebmMuxer( 180 webm_muxer_.reset(new media::WebmMuxer(
150 use_vp9_ ? media::kCodecVP9 : media::kCodecVP8, use_video_tracks, 181 CodecIdToMediaVideoCodec(codec_id_), use_video_tracks, use_audio_tracks,
151 use_audio_tracks, base::Bind(&MediaRecorderHandler::WriteData, 182 base::Bind(&MediaRecorderHandler::WriteData,
152 weak_factory_.GetWeakPtr()))); 183 weak_factory_.GetWeakPtr())));
153 184
154 if (use_video_tracks) { 185 if (use_video_tracks) {
155 // TODO(mcasas): The muxer API supports only one video track. Extend it to 186 // TODO(mcasas): The muxer API supports only one video track. Extend it to
156 // several video tracks, see http://crbug.com/528523. 187 // several video tracks, see http://crbug.com/528523.
157 LOG_IF(WARNING, video_tracks.size() > 1u) 188 LOG_IF(WARNING, video_tracks.size() > 1u)
158 << "Recording multiple video tracks is not implemented. " 189 << "Recording multiple video tracks is not implemented. "
159 << "Only recording first video track."; 190 << "Only recording first video track.";
160 const blink::WebMediaStreamTrack& video_track = video_tracks[0]; 191 const blink::WebMediaStreamTrack& video_track = video_tracks[0];
161 if (video_track.isNull()) 192 if (video_track.isNull())
162 return false; 193 return false;
163 194
164 const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_cb = 195 const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_cb =
165 media::BindToCurrentLoop(base::Bind( 196 media::BindToCurrentLoop(base::Bind(
166 &MediaRecorderHandler::OnEncodedVideo, weak_factory_.GetWeakPtr())); 197 &MediaRecorderHandler::OnEncodedVideo, weak_factory_.GetWeakPtr()));
167 198
168 video_recorders_.push_back(new VideoTrackRecorder( 199 video_recorders_.push_back(new VideoTrackRecorder(
169 use_vp9_ ? VideoTrackRecorder::CodecId::VP9 200 codec_id_, video_track, on_encoded_video_cb, video_bits_per_second_));
170 : VideoTrackRecorder::CodecId::VP8,
171 video_track, on_encoded_video_cb, video_bits_per_second_));
172 } 201 }
173 202
174 if (use_audio_tracks) { 203 if (use_audio_tracks) {
175 // TODO(ajose): The muxer API supports only one audio track. Extend it to 204 // TODO(ajose): The muxer API supports only one audio track. Extend it to
176 // several tracks. 205 // several tracks.
177 LOG_IF(WARNING, audio_tracks.size() > 1u) 206 LOG_IF(WARNING, audio_tracks.size() > 1u)
178 << "Recording multiple audio" 207 << "Recording multiple audio"
179 << " tracks is not implemented. Only recording first audio track."; 208 << " tracks is not implemented. Only recording first audio track.";
180 const blink::WebMediaStreamTrack& audio_track = audio_tracks[0]; 209 const blink::WebMediaStreamTrack& audio_track = audio_tracks[0];
181 if (audio_track.isNull()) 210 if (audio_track.isNull())
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 recorder->OnData(audio_bus, timestamp); 306 recorder->OnData(audio_bus, timestamp);
278 } 307 }
279 308
280 void MediaRecorderHandler::SetAudioFormatForTesting( 309 void MediaRecorderHandler::SetAudioFormatForTesting(
281 const media::AudioParameters& params) { 310 const media::AudioParameters& params) {
282 for (auto* recorder : audio_recorders_) 311 for (auto* recorder : audio_recorders_)
283 recorder->OnSetFormat(params); 312 recorder->OnSetFormat(params);
284 } 313 }
285 314
286 } // namespace content 315 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/media_recorder_handler.h ('k') | content/renderer/media/media_recorder_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698