| OLD | NEW | 
|---|
| 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 "media/capture/webm_muxer.h" | 5 #include "media/capture/webm_muxer.h" | 
| 6 | 6 | 
| 7 #include <limits> | 7 #include <limits> | 
| 8 | 8 | 
| 9 #include "base/bind.h" | 9 #include "base/bind.h" | 
| 10 #include "media/base/video_frame.h" | 10 #include "media/base/video_frame.h" | 
| 11 | 11 | 
| 12 namespace media { | 12 namespace media { | 
| 13 | 13 | 
| 14 static double GetFrameRate(const scoped_refptr<VideoFrame>& video_frame) { | 14 static double GetFrameRate(const scoped_refptr<VideoFrame>& video_frame) { | 
| 15   double frame_rate = 0.0f; | 15   double frame_rate = 0.0f; | 
| 16   base::IgnoreResult(video_frame->metadata()->GetDouble( | 16   base::IgnoreResult(video_frame->metadata()->GetDouble( | 
| 17       VideoFrameMetadata::FRAME_RATE, &frame_rate)); | 17       VideoFrameMetadata::FRAME_RATE, &frame_rate)); | 
| 18   return frame_rate; | 18   return frame_rate; | 
| 19 } | 19 } | 
| 20 | 20 | 
| 21 WebmMuxer::WebmMuxer(const WriteDataCB& write_data_callback) | 21 WebmMuxer::WebmMuxer(const WriteDataCB& write_data_callback) | 
| 22     : track_index_(0), | 22     : track_index_(0), | 
| 23       write_data_callback_(write_data_callback), | 23       write_data_callback_(write_data_callback), | 
| 24       position_(0) { | 24       position_(0) { | 
| 25   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 26   DCHECK(!write_data_callback_.is_null()); | 25   DCHECK(!write_data_callback_.is_null()); | 
| 27   segment_.Init(this); | 26   // Creation is done on a different thread than main activities. | 
| 28   segment_.set_mode(mkvmuxer::Segment::kLive); | 27   io_thread_checker_.DetachFromThread(); | 
| 29   segment_.OutputCues(false); |  | 
| 30 |  | 
| 31   mkvmuxer::SegmentInfo* const info = segment_.GetSegmentInfo(); |  | 
| 32   info->set_writing_app("Chrome"); |  | 
| 33   info->set_muxing_app("Chrome"); |  | 
| 34 } | 28 } | 
| 35 | 29 | 
| 36 WebmMuxer::~WebmMuxer() { | 30 WebmMuxer::~WebmMuxer() { | 
| 37   DCHECK(thread_checker_.CalledOnValidThread()); | 31   // No need to segment_.Finalize() since is not Seekable(), i.e. a live stream. | 
| 38   segment_.Finalize(); |  | 
| 39 } | 32 } | 
| 40 | 33 | 
| 41 void WebmMuxer::OnEncodedVideo(const scoped_refptr<VideoFrame>& video_frame, | 34 void WebmMuxer::OnEncodedVideo(const scoped_refptr<VideoFrame>& video_frame, | 
| 42                                const base::StringPiece& encoded_data, | 35                                const base::StringPiece& encoded_data, | 
| 43                                base::TimeTicks timestamp, | 36                                base::TimeTicks timestamp, | 
| 44                                bool is_key_frame) { | 37                                bool is_key_frame) { | 
| 45   DCHECK(thread_checker_.CalledOnValidThread()); | 38   DVLOG(1) << __FUNCTION__ << " - " << encoded_data.size() << "B"; | 
|  | 39   DCHECK(io_thread_checker_.CalledOnValidThread()); | 
| 46   if (!track_index_) { | 40   if (!track_index_) { | 
| 47     // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. | 41     // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. | 
| 48     // http://www.matroska.org/technical/specs/index.html#Tracks | 42     // http://www.matroska.org/technical/specs/index.html#Tracks | 
| 49     AddVideoTrack(video_frame->visible_rect().size(), | 43     AddVideoTrack(video_frame->visible_rect().size(), | 
| 50                   GetFrameRate(video_frame)); | 44                   GetFrameRate(video_frame)); | 
| 51     first_frame_timestamp_ = timestamp; | 45     first_frame_timestamp_ = timestamp; | 
| 52   } | 46   } | 
| 53   segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data.data()), | 47   segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data.data()), | 
| 54                     encoded_data.size(), | 48                     encoded_data.size(), | 
| 55                     track_index_, | 49                     track_index_, | 
| 56                     (timestamp - first_frame_timestamp_).InMilliseconds(), | 50                     (timestamp - first_frame_timestamp_).InMilliseconds(), | 
| 57                     is_key_frame); | 51                     is_key_frame); | 
| 58 } | 52 } | 
| 59 | 53 | 
| 60 void WebmMuxer::AddVideoTrack(const gfx::Size& frame_size, double frame_rate) { | 54 void WebmMuxer::AddVideoTrack(const gfx::Size& frame_size, double frame_rate) { | 
| 61   DCHECK(thread_checker_.CalledOnValidThread()); | 55   DCHECK(io_thread_checker_.CalledOnValidThread()); | 
|  | 56 | 
|  | 57   segment_.Init(this); | 
|  | 58   segment_.set_mode(mkvmuxer::Segment::kLive); | 
|  | 59   segment_.OutputCues(false); | 
|  | 60 | 
|  | 61   mkvmuxer::SegmentInfo* const info = segment_.GetSegmentInfo(); | 
|  | 62   info->set_writing_app("Chrome"); | 
|  | 63   info->set_muxing_app("Chrome"); | 
|  | 64 | 
| 62   DCHECK_EQ(track_index_, 0u); | 65   DCHECK_EQ(track_index_, 0u); | 
| 63   track_index_ = | 66   track_index_ = | 
| 64       segment_.AddVideoTrack(frame_size.width(), frame_size.height(), 0); | 67       segment_.AddVideoTrack(frame_size.width(), frame_size.height(), 0); | 
| 65   DCHECK_GT(track_index_, 0u); | 68   DCHECK_GT(track_index_, 0u); | 
| 66 | 69 | 
| 67   mkvmuxer::VideoTrack* const video_track = | 70   mkvmuxer::VideoTrack* const video_track = | 
| 68       reinterpret_cast<mkvmuxer::VideoTrack*>( | 71       reinterpret_cast<mkvmuxer::VideoTrack*>( | 
| 69           segment_.GetTrackByNumber(track_index_)); | 72           segment_.GetTrackByNumber(track_index_)); | 
| 70   DCHECK(video_track); | 73   DCHECK(video_track); | 
| 71   video_track->set_codec_id(mkvmuxer::Tracks::kVp8CodecId); | 74   video_track->set_codec_id(mkvmuxer::Tracks::kVp8CodecId); | 
| 72   DCHECK_EQ(video_track->crop_right(), 0ull); | 75   DCHECK_EQ(video_track->crop_right(), 0ull); | 
| 73   DCHECK_EQ(video_track->crop_left(), 0ull); | 76   DCHECK_EQ(video_track->crop_left(), 0ull); | 
| 74   DCHECK_EQ(video_track->crop_top(), 0ull); | 77   DCHECK_EQ(video_track->crop_top(), 0ull); | 
| 75   DCHECK_EQ(video_track->crop_bottom(), 0ull); | 78   DCHECK_EQ(video_track->crop_bottom(), 0ull); | 
| 76 | 79 | 
| 77   video_track->set_frame_rate(frame_rate); | 80   video_track->set_frame_rate(frame_rate); | 
| 78   video_track->set_default_duration(base::Time::kMicrosecondsPerSecond / | 81   video_track->set_default_duration(base::Time::kMicrosecondsPerSecond / | 
| 79                                     frame_rate); | 82                                     frame_rate); | 
| 80   // Segment's timestamps should be in milliseconds, DCHECK it. See | 83   // Segment's timestamps should be in milliseconds, DCHECK it. See | 
| 81   // http://www.webmproject.org/docs/container/#muxer-guidelines | 84   // http://www.webmproject.org/docs/container/#muxer-guidelines | 
| 82   DCHECK_EQ(segment_.GetSegmentInfo()->timecode_scale(), 1000000ull); | 85   DCHECK_EQ(segment_.GetSegmentInfo()->timecode_scale(), 1000000ull); | 
| 83 } | 86 } | 
| 84 | 87 | 
| 85 mkvmuxer::int32 WebmMuxer::Write(const void* buf, mkvmuxer::uint32 len) { | 88 mkvmuxer::int32 WebmMuxer::Write(const void* buf, mkvmuxer::uint32 len) { | 
| 86   DCHECK(thread_checker_.CalledOnValidThread()); | 89   DCHECK(io_thread_checker_.CalledOnValidThread()); | 
| 87   DCHECK(buf); | 90   DCHECK(buf); | 
| 88   write_data_callback_.Run(base::StringPiece(reinterpret_cast<const char*>(buf), | 91   write_data_callback_.Run(base::StringPiece(reinterpret_cast<const char*>(buf), | 
| 89                                              len)); | 92                                              len)); | 
| 90   position_ += len; | 93   position_ += len; | 
| 91   return 0; | 94   return 0; | 
| 92 } | 95 } | 
| 93 | 96 | 
| 94 mkvmuxer::int64 WebmMuxer::Position() const { | 97 mkvmuxer::int64 WebmMuxer::Position() const { | 
| 95   return position_.ValueOrDie(); | 98   return position_.ValueOrDie(); | 
| 96 } | 99 } | 
| 97 | 100 | 
| 98 mkvmuxer::int32 WebmMuxer::Position(mkvmuxer::int64 position) { | 101 mkvmuxer::int32 WebmMuxer::Position(mkvmuxer::int64 position) { | 
| 99   // The stream is not Seekable() so indicate we cannot set the position. | 102   // The stream is not Seekable() so indicate we cannot set the position. | 
| 100   return -1; | 103   return -1; | 
| 101 } | 104 } | 
| 102 | 105 | 
| 103 bool WebmMuxer::Seekable() const { | 106 bool WebmMuxer::Seekable() const { | 
| 104   return false; | 107   return false; | 
| 105 } | 108 } | 
| 106 | 109 | 
| 107 void WebmMuxer::ElementStartNotify(mkvmuxer::uint64 element_id, | 110 void WebmMuxer::ElementStartNotify(mkvmuxer::uint64 element_id, | 
| 108                                    mkvmuxer::int64 position) { | 111                                    mkvmuxer::int64 position) { | 
| 109   // This method gets pinged before items are sent to |write_data_callback_|. | 112   // This method gets pinged before items are sent to |write_data_callback_|. | 
| 110   DCHECK_GE(position, position_.ValueOrDefault(0)) | 113   DCHECK_GE(position, position_.ValueOrDefault(0)) | 
| 111       << "Can't go back in a live WebM stream."; | 114       << "Can't go back in a live WebM stream."; | 
| 112 } | 115 } | 
| 113 | 116 | 
| 114 }  // namespace media | 117 }  // namespace media | 
| OLD | NEW | 
|---|