| 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/muxers/webm_muxer.h" | 5 #include "media/muxers/webm_muxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| 11 #include "media/base/audio_parameters.h" | 11 #include "media/base/audio_parameters.h" |
| 12 #include "media/base/limits.h" | 12 #include "media/base/limits.h" |
| 13 #include "media/base/video_frame.h" | 13 #include "media/base/video_frame.h" |
| 14 #include "media/filters/opus_constants.h" | 14 #include "media/filters/opus_constants.h" |
| 15 #include "ui/gfx/geometry/size.h" | |
| 16 | 15 |
| 17 namespace media { | 16 namespace media { |
| 18 | 17 |
| 19 namespace { | 18 namespace { |
| 20 | 19 |
| 21 void WriteOpusHeader(const media::AudioParameters& params, uint8_t* header) { | 20 void WriteOpusHeader(const media::AudioParameters& params, uint8_t* header) { |
| 22 // See https://wiki.xiph.org/OggOpus#ID_Header. | 21 // See https://wiki.xiph.org/OggOpus#ID_Header. |
| 23 // Set magic signature. | 22 // Set magic signature. |
| 24 std::string label = "OpusHead"; | 23 std::string label = "OpusHead"; |
| 25 memcpy(header + OPUS_EXTRADATA_LABEL_OFFSET, label.c_str(), label.size()); | 24 memcpy(header + OPUS_EXTRADATA_LABEL_OFFSET, label.c_str(), label.size()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 50 // Set the actual stream map. | 49 // Set the actual stream map. |
| 51 for (int i = 0; i < params.channels(); ++i) { | 50 for (int i = 0; i < params.channels(); ++i) { |
| 52 header[OPUS_EXTRADATA_STREAM_MAP_OFFSET + i] = | 51 header[OPUS_EXTRADATA_STREAM_MAP_OFFSET + i] = |
| 53 kOpusVorbisChannelMap[params.channels() - 1][i]; | 52 kOpusVorbisChannelMap[params.channels() - 1][i]; |
| 54 } | 53 } |
| 55 } else { | 54 } else { |
| 56 header[OPUS_EXTRADATA_CHANNEL_MAPPING_OFFSET] = 0; | 55 header[OPUS_EXTRADATA_CHANNEL_MAPPING_OFFSET] = 0; |
| 57 } | 56 } |
| 58 } | 57 } |
| 59 | 58 |
| 60 static double GetFrameRate(const scoped_refptr<VideoFrame>& video_frame) { | 59 static double GetFrameRate(const WebmMuxer::VideoParameters& params) { |
| 61 const double kZeroFrameRate = 0.0; | 60 const double kZeroFrameRate = 0.0; |
| 62 const double kDefaultFrameRate = 30.0; | 61 const double kDefaultFrameRate = 30.0; |
| 63 | 62 |
| 64 double frame_rate = kDefaultFrameRate; | 63 double frame_rate = params.frame_rate; |
| 65 if (!video_frame->metadata()->GetDouble(VideoFrameMetadata::FRAME_RATE, | 64 if (frame_rate <= kZeroFrameRate || |
| 66 &frame_rate) || | |
| 67 frame_rate <= kZeroFrameRate || | |
| 68 frame_rate > media::limits::kMaxFramesPerSecond) { | 65 frame_rate > media::limits::kMaxFramesPerSecond) { |
| 69 frame_rate = kDefaultFrameRate; | 66 frame_rate = kDefaultFrameRate; |
| 70 } | 67 } |
| 71 return frame_rate; | 68 return frame_rate; |
| 72 } | 69 } |
| 73 | 70 |
| 74 static const char kH264CodecId[] = "V_MPEG4/ISO/AVC"; | 71 static const char kH264CodecId[] = "V_MPEG4/ISO/AVC"; |
| 75 | 72 |
| 76 static const char* MkvCodeIcForMediaVideoCodecId(VideoCodec video_codec) { | 73 static const char* MkvCodeIcForMediaVideoCodecId(VideoCodec video_codec) { |
| 77 switch (video_codec) { | 74 switch (video_codec) { |
| 78 case kCodecVP8: | 75 case kCodecVP8: |
| 79 return mkvmuxer::Tracks::kVp8CodecId; | 76 return mkvmuxer::Tracks::kVp8CodecId; |
| 80 case kCodecVP9: | 77 case kCodecVP9: |
| 81 return mkvmuxer::Tracks::kVp9CodecId; | 78 return mkvmuxer::Tracks::kVp9CodecId; |
| 82 case kCodecH264: | 79 case kCodecH264: |
| 83 return kH264CodecId; | 80 return kH264CodecId; |
| 84 default: | 81 default: |
| 85 NOTREACHED() << "Unsupported codec " << GetCodecName(video_codec); | 82 NOTREACHED() << "Unsupported codec " << GetCodecName(video_codec); |
| 86 return ""; | 83 return ""; |
| 87 } | 84 } |
| 88 } | 85 } |
| 89 | 86 |
| 90 } // anonymous namespace | 87 } // anonymous namespace |
| 91 | 88 |
| 89 WebmMuxer::VideoParameters::VideoParameters( |
| 90 scoped_refptr<media::VideoFrame> frame) { |
| 91 frame_size = frame->visible_rect().size(); |
| 92 frame_rate = 0.0; |
| 93 ignore_result(frame->metadata()->GetDouble(VideoFrameMetadata::FRAME_RATE, |
| 94 &frame_rate)); |
| 95 } |
| 96 |
| 97 WebmMuxer::VideoParameters::~VideoParameters() {} |
| 98 |
| 92 WebmMuxer::WebmMuxer(VideoCodec codec, | 99 WebmMuxer::WebmMuxer(VideoCodec codec, |
| 93 bool has_video, | 100 bool has_video, |
| 94 bool has_audio, | 101 bool has_audio, |
| 95 const WriteDataCB& write_data_callback) | 102 const WriteDataCB& write_data_callback) |
| 96 : video_codec_(codec), | 103 : video_codec_(codec), |
| 97 video_track_index_(0), | 104 video_track_index_(0), |
| 98 audio_track_index_(0), | 105 audio_track_index_(0), |
| 99 has_video_(has_video), | 106 has_video_(has_video), |
| 100 has_audio_(has_audio), | 107 has_audio_(has_audio), |
| 101 write_data_callback_(write_data_callback), | 108 write_data_callback_(write_data_callback), |
| (...skipping 15 matching lines...) Expand all Loading... |
| 117 thread_checker_.DetachFromThread(); | 124 thread_checker_.DetachFromThread(); |
| 118 } | 125 } |
| 119 | 126 |
| 120 WebmMuxer::~WebmMuxer() { | 127 WebmMuxer::~WebmMuxer() { |
| 121 // No need to segment_.Finalize() since is not Seekable(), i.e. a live | 128 // No need to segment_.Finalize() since is not Seekable(), i.e. a live |
| 122 // stream, but is a good practice. | 129 // stream, but is a good practice. |
| 123 DCHECK(thread_checker_.CalledOnValidThread()); | 130 DCHECK(thread_checker_.CalledOnValidThread()); |
| 124 segment_.Finalize(); | 131 segment_.Finalize(); |
| 125 } | 132 } |
| 126 | 133 |
| 127 void WebmMuxer::OnEncodedVideo(const scoped_refptr<VideoFrame>& video_frame, | 134 void WebmMuxer::OnEncodedVideo(const VideoParameters& params, |
| 128 std::unique_ptr<std::string> encoded_data, | 135 std::unique_ptr<std::string> encoded_data, |
| 129 base::TimeTicks timestamp, | 136 base::TimeTicks timestamp, |
| 130 bool is_key_frame) { | 137 bool is_key_frame) { |
| 131 DVLOG(1) << __func__ << " - " << encoded_data->size() << "B"; | 138 DVLOG(1) << __func__ << " - " << encoded_data->size() << "B"; |
| 132 DCHECK(thread_checker_.CalledOnValidThread()); | 139 DCHECK(thread_checker_.CalledOnValidThread()); |
| 133 | 140 |
| 134 if (!video_track_index_) { | 141 if (!video_track_index_) { |
| 135 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. | 142 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. |
| 136 // http://www.matroska.org/technical/specs/index.html#Tracks | 143 // http://www.matroska.org/technical/specs/index.html#Tracks |
| 137 AddVideoTrack(video_frame->visible_rect().size(), | 144 AddVideoTrack(params.frame_size, GetFrameRate(params)); |
| 138 GetFrameRate(video_frame)); | |
| 139 if (first_frame_timestamp_video_.is_null()) | 145 if (first_frame_timestamp_video_.is_null()) |
| 140 first_frame_timestamp_video_ = timestamp; | 146 first_frame_timestamp_video_ = timestamp; |
| 141 } | 147 } |
| 142 | 148 |
| 143 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 | 149 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 |
| 144 if (has_audio_ && !audio_track_index_) { | 150 if (has_audio_ && !audio_track_index_) { |
| 145 DVLOG(1) << __func__ << ": delaying until audio track ready."; | 151 DVLOG(1) << __func__ << ": delaying until audio track ready."; |
| 146 if (is_key_frame) // Upon Key frame reception, empty the encoded queue. | 152 if (is_key_frame) // Upon Key frame reception, empty the encoded queue. |
| 147 encoded_frames_queue_.clear(); | 153 encoded_frames_queue_.clear(); |
| 148 | 154 |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 | 331 |
| 326 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame( | 332 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame( |
| 327 std::unique_ptr<std::string> data, | 333 std::unique_ptr<std::string> data, |
| 328 base::TimeTicks timestamp, | 334 base::TimeTicks timestamp, |
| 329 bool is_keyframe) | 335 bool is_keyframe) |
| 330 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {} | 336 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {} |
| 331 | 337 |
| 332 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {} | 338 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {} |
| 333 | 339 |
| 334 } // namespace media | 340 } // namespace media |
| OLD | NEW |