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
3 // found in the LICENSE file.
5 #include "media/capture/webm_muxer.h"
8 #include "media/base/limits.h"
9 #include "media/base/video_frame.h"
13 static double GetFrameRate(const scoped_refptr
<VideoFrame
>& video_frame
) {
14 const double kZeroFrameRate
= 0.0;
15 const double kDefaultFrameRate
= 30.0;
17 double frame_rate
= kDefaultFrameRate
;
18 if (!video_frame
->metadata()->GetDouble(
19 VideoFrameMetadata::FRAME_RATE
, &frame_rate
) ||
20 frame_rate
<= kZeroFrameRate
||
21 frame_rate
> media::limits::kMaxFramesPerSecond
) {
22 frame_rate
= kDefaultFrameRate
;
27 WebmMuxer::WebmMuxer(const WriteDataCB
& write_data_callback
)
29 write_data_callback_(write_data_callback
),
31 DCHECK(thread_checker_
.CalledOnValidThread());
32 DCHECK(!write_data_callback_
.is_null());
34 segment_
.set_mode(mkvmuxer::Segment::kLive
);
35 segment_
.OutputCues(false);
37 mkvmuxer::SegmentInfo
* const info
= segment_
.GetSegmentInfo();
38 info
->set_writing_app("Chrome");
39 info
->set_muxing_app("Chrome");
42 WebmMuxer::~WebmMuxer() {
43 DCHECK(thread_checker_
.CalledOnValidThread());
47 void WebmMuxer::OnEncodedVideo(const scoped_refptr
<VideoFrame
>& video_frame
,
48 const base::StringPiece
& encoded_data
,
49 base::TimeTicks timestamp
,
51 DCHECK(thread_checker_
.CalledOnValidThread());
53 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case.
54 // http://www.matroska.org/technical/specs/index.html#Tracks
55 AddVideoTrack(video_frame
->visible_rect().size(),
56 GetFrameRate(video_frame
));
57 first_frame_timestamp_
= timestamp
;
59 segment_
.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data
.data()),
62 (timestamp
- first_frame_timestamp_
).InMicroseconds() *
63 base::Time::kNanosecondsPerMicrosecond
,
67 void WebmMuxer::AddVideoTrack(const gfx::Size
& frame_size
, double frame_rate
) {
68 DCHECK(thread_checker_
.CalledOnValidThread());
69 DCHECK_EQ(track_index_
, 0u);
71 segment_
.AddVideoTrack(frame_size
.width(), frame_size
.height(), 0);
72 DCHECK_GT(track_index_
, 0u);
74 mkvmuxer::VideoTrack
* const video_track
=
75 reinterpret_cast<mkvmuxer::VideoTrack
*>(
76 segment_
.GetTrackByNumber(track_index_
));
78 video_track
->set_codec_id(mkvmuxer::Tracks::kVp8CodecId
);
79 DCHECK_EQ(video_track
->crop_right(), 0ull);
80 DCHECK_EQ(video_track
->crop_left(), 0ull);
81 DCHECK_EQ(video_track
->crop_top(), 0ull);
82 DCHECK_EQ(video_track
->crop_bottom(), 0ull);
84 video_track
->set_frame_rate(frame_rate
);
85 video_track
->set_default_duration(base::Time::kNanosecondsPerSecond
/
87 // Segment's timestamps should be in milliseconds, DCHECK it. See
88 // http://www.webmproject.org/docs/container/#muxer-guidelines
89 DCHECK_EQ(segment_
.GetSegmentInfo()->timecode_scale(), 1000000ull);
92 mkvmuxer::int32
WebmMuxer::Write(const void* buf
, mkvmuxer::uint32 len
) {
93 DCHECK(thread_checker_
.CalledOnValidThread());
95 write_data_callback_
.Run(base::StringPiece(reinterpret_cast<const char*>(buf
),
101 mkvmuxer::int64
WebmMuxer::Position() const {
102 return position_
.ValueOrDie();
105 mkvmuxer::int32
WebmMuxer::Position(mkvmuxer::int64 position
) {
106 // The stream is not Seekable() so indicate we cannot set the position.
110 bool WebmMuxer::Seekable() const {
114 void WebmMuxer::ElementStartNotify(mkvmuxer::uint64 element_id
,
115 mkvmuxer::int64 position
) {
116 // This method gets pinged before items are sent to |write_data_callback_|.
117 DCHECK_GE(position
, position_
.ValueOrDefault(0))
118 << "Can't go back in a live WebM stream.";