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

Side by Side Diff: media/capture/video/file_video_capture_device.cc

Issue 1291933002: File video capture device supports MJPEG format (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: refactor Created 5 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/video/file_video_capture_device.h" 5 #include "media/capture/video/file_video_capture_device.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_piece.h" 9 #include "base/strings/string_piece.h"
10 #include "media/base/video_capture_types.h" 10 #include "media/base/video_capture_types.h"
11 #include "media/filters/jpeg_parser.h"
11 12
12 namespace media { 13 namespace media {
14
13 static const int kY4MHeaderMaxSize = 200; 15 static const int kY4MHeaderMaxSize = 200;
14 static const char kY4MSimpleFrameDelimiter[] = "FRAME"; 16 static const char kY4MSimpleFrameDelimiter[] = "FRAME";
15 static const int kY4MSimpleFrameDelimiterSize = 6; 17 static const int kY4MSimpleFrameDelimiterSize = 6;
18 static const int kMJpegFrameRate = 30;
mcasas 2015/08/19 22:17:35 float, 30.0f
henryhsu 2015/08/20 03:18:56 Done.
16 19
17 int ParseY4MInt(const base::StringPiece& token) { 20 FileVideoCaptureDevice::VideoFileParser::VideoFileParser(
21 const base::FilePath& file_path)
22 : file_path_(file_path),
23 frame_size_(0),
24 current_byte_index_(0),
25 first_frame_byte_index_(0) {}
26
27 FileVideoCaptureDevice::VideoFileParser::~VideoFileParser() {}
28
29 FileVideoCaptureDevice::Y4mFileParser::Y4mFileParser(
30 const base::FilePath& file_path)
31 : VideoFileParser(file_path) {}
32
33 FileVideoCaptureDevice::Y4mFileParser::~Y4mFileParser() {}
34
35 bool FileVideoCaptureDevice::Y4mFileParser::Initialize(
36 media::VideoCaptureFormat* capture_format) {
37 file_.reset(new base::File(file_path_,
38 base::File::FLAG_OPEN | base::File::FLAG_READ));
39 if (!file_->IsValid()) {
40 DLOG(ERROR) << file_path_.value() << ", error: "
41 << base::File::ErrorToString(file_->error_details());
42 return false;
43 }
44
45 std::string header(kY4MHeaderMaxSize, 0);
kcwu 2015/08/19 11:29:38 s/0/'\0'/
henryhsu 2015/08/20 03:18:57 Done.
46 file_->Read(0, &header[0], kY4MHeaderMaxSize - 1);
kcwu 2015/08/19 11:29:38 s/kY4MHeaderMaxSize - 1/header.size()/
henryhsu 2015/08/20 03:18:57 Done.
47 const size_t header_end = header.find(kY4MSimpleFrameDelimiter);
48 CHECK_NE(header_end, header.npos);
49
50 ParseY4MTags(header, capture_format);
51 first_frame_byte_index_ = header_end + kY4MSimpleFrameDelimiterSize;
52 current_byte_index_ = first_frame_byte_index_;
53 frame_size_ = capture_format->ImageAllocationSize();
54 video_frame_.reset(new uint8[frame_size_]);
kcwu 2015/08/19 11:29:38 uint8_t
henryhsu 2015/08/20 03:18:57 Done.
55 return true;
56 }
57
58 const uint8_t* FileVideoCaptureDevice::Y4mFileParser::GetNextFrame(
59 int* frame_size) {
60 int result =
61 file_->Read(current_byte_index_,
62 reinterpret_cast<char*>(video_frame_.get()), frame_size_);
63
64 // If we passed EOF to base::File, it will return 0 read characters. In that
65 // case, reset the pointer andd read again.
kcwu 2015/08/19 11:29:38 s/andd/and/
henryhsu 2015/08/20 03:18:57 Done.
66 if (result != frame_size_) {
67 CHECK_EQ(result, 0);
68 current_byte_index_ = first_frame_byte_index_;
69 CHECK_EQ(
70 file_->Read(current_byte_index_,
71 reinterpret_cast<char*>(video_frame_.get()), frame_size_),
72 frame_size_);
73 } else {
74 current_byte_index_ += frame_size_ + kY4MSimpleFrameDelimiterSize;
75 }
76 *frame_size = frame_size_;
77 return video_frame_.get();
78 }
79
80 int FileVideoCaptureDevice::Y4mFileParser::ParseY4MInt(
mcasas 2015/08/19 22:17:34 This method should be a file function as before.
henryhsu 2015/08/20 03:18:56 Done.
81 const base::StringPiece& token) {
18 int temp_int; 82 int temp_int;
19 CHECK(base::StringToInt(token, &temp_int)) << token; 83 CHECK(base::StringToInt(token, &temp_int)) << token;
20 return temp_int; 84 return temp_int;
21 } 85 }
22 86
23 // Extract numerator and denominator out of a token that must have the aspect 87 // Extract numerator and denominator out of a token that must have the aspect
24 // numerator:denominator, both integer numbers. 88 // numerator:denominator, both integer numbers.
25 void ParseY4MRational(const base::StringPiece& token, 89 void FileVideoCaptureDevice::Y4mFileParser::ParseY4MRational(
mcasas 2015/08/19 22:17:34 Same: This method should be a file function as bef
henryhsu 2015/08/20 03:18:57 Done.
26 int* numerator, 90 const base::StringPiece& token,
27 int* denominator) { 91 int* numerator,
92 int* denominator) {
28 size_t index_divider = token.find(':'); 93 size_t index_divider = token.find(':');
29 CHECK_NE(index_divider, token.npos); 94 CHECK_NE(index_divider, token.npos);
30 *numerator = ParseY4MInt(token.substr(0, index_divider)); 95 *numerator = ParseY4MInt(token.substr(0, index_divider));
31 *denominator = ParseY4MInt(token.substr(index_divider + 1, token.length())); 96 *denominator = ParseY4MInt(token.substr(index_divider + 1, token.length()));
32 CHECK(*denominator); 97 CHECK(*denominator);
33 } 98 }
34 99
35 // This function parses the ASCII string in |header| as belonging to a Y4M file, 100 // This function parses the ASCII string in |header| as belonging to a Y4M file,
36 // returning the collected format in |video_format|. For a non authoritative 101 // returning the collected format in |video_format|. For a non authoritative
37 // explanation of the header format, check 102 // explanation of the header format, check
38 // http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 103 // http://wiki.multimedia.cx/index.php?title=YUV4MPEG2
39 // Restrictions: Only interlaced I420 pixel format is supported, and pixel 104 // Restrictions: Only interlaced I420 pixel format is supported, and pixel
40 // aspect ratio is ignored. 105 // aspect ratio is ignored.
41 // Implementation notes: Y4M header should end with an ASCII 0x20 (whitespace) 106 // Implementation notes: Y4M header should end with an ASCII 0x20 (whitespace)
42 // character, however all examples mentioned in the Y4M header description end 107 // character, however all examples mentioned in the Y4M header description end
43 // with a newline character instead. Also, some headers do _not_ specify pixel 108 // with a newline character instead. Also, some headers do _not_ specify pixel
44 // format, in this case it means I420. 109 // format, in this case it means I420.
45 // This code was inspired by third_party/libvpx/.../y4minput.* . 110 // This code was inspired by third_party/libvpx/.../y4minput.* .
46 void ParseY4MTags(const std::string& file_header, 111 void FileVideoCaptureDevice::Y4mFileParser::ParseY4MTags(
mcasas 2015/08/19 22:17:34 Same: This method should be a file function as bef
henryhsu 2015/08/20 03:18:57 Done.
47 media::VideoCaptureFormat* video_format) { 112 const std::string& file_header,
48 video_format->pixel_format = media::VIDEO_CAPTURE_PIXEL_FORMAT_I420; 113 media::VideoCaptureFormat* video_format) {
49 video_format->frame_size.set_width(0); 114 media::VideoCaptureFormat format;
50 video_format->frame_size.set_height(0); 115 format.pixel_format = media::VIDEO_CAPTURE_PIXEL_FORMAT_I420;
51 size_t index = 0; 116 size_t index = 0;
52 size_t blank_position = 0; 117 size_t blank_position = 0;
53 base::StringPiece token; 118 base::StringPiece token;
54 while ((blank_position = file_header.find_first_of("\n ", index)) != 119 while ((blank_position = file_header.find_first_of("\n ", index)) !=
55 std::string::npos) { 120 std::string::npos) {
56 // Every token is supposed to have an identifier letter and a bunch of 121 // Every token is supposed to have an identifier letter and a bunch of
57 // information immediately after, which we extract into a |token| here. 122 // information immediately after, which we extract into a |token| here.
58 token = 123 token =
59 base::StringPiece(&file_header[index + 1], blank_position - index - 1); 124 base::StringPiece(&file_header[index + 1], blank_position - index - 1);
60 CHECK(!token.empty()); 125 CHECK(!token.empty());
61 switch (file_header[index]) { 126 switch (file_header[index]) {
62 case 'W': 127 case 'W':
63 video_format->frame_size.set_width(ParseY4MInt(token)); 128 format.frame_size.set_width(ParseY4MInt(token));
64 break; 129 break;
65 case 'H': 130 case 'H':
66 video_format->frame_size.set_height(ParseY4MInt(token)); 131 format.frame_size.set_height(ParseY4MInt(token));
67 break; 132 break;
68 case 'F': { 133 case 'F': {
69 // If the token is "FRAME", it means we have finished with the header. 134 // If the token is "FRAME", it means we have finished with the header.
70 if (token[0] == 'R') 135 if (token[0] == 'R')
71 break; 136 break;
72 int fps_numerator, fps_denominator; 137 int fps_numerator, fps_denominator;
73 ParseY4MRational(token, &fps_numerator, &fps_denominator); 138 ParseY4MRational(token, &fps_numerator, &fps_denominator);
74 video_format->frame_rate = fps_numerator / fps_denominator; 139 format.frame_rate = fps_numerator / fps_denominator;
75 break; 140 break;
76 } 141 }
77 case 'I': 142 case 'I':
78 // Interlacing is ignored, but we don't like mixed modes. 143 // Interlacing is ignored, but we don't like mixed modes.
79 CHECK_NE(token[0], 'm'); 144 CHECK_NE(token[0], 'm');
80 break; 145 break;
81 case 'A': 146 case 'A':
82 // Pixel aspect ratio ignored. 147 // Pixel aspect ratio ignored.
83 break; 148 break;
84 case 'C': 149 case 'C':
85 CHECK(token == "420" || token == "420jpeg" || token == "420paldv") 150 CHECK(token == "420" || token == "420jpeg" || token == "420paldv")
86 << token; // Only I420 is supported, and we fudge the variants. 151 << token; // Only I420 is supported, and we fudge the variants.
87 break;
88 default: 152 default:
kcwu 2015/08/19 11:29:38 why removed break; above this line?
henryhsu 2015/08/20 03:18:56 Thanks.
89 break; 153 break;
90 } 154 }
91 // We're done if we have found a newline character right after the token. 155 // We're done if we have found a newline character right after the token.
92 if (file_header[blank_position] == '\n') 156 if (file_header[blank_position] == '\n')
93 break; 157 break;
94 index = blank_position + 1; 158 index = blank_position + 1;
95 } 159 }
96 // Last video format semantic correctness check before sending it back. 160 // Last video format semantic correctness check before sending it back.
97 CHECK(video_format->IsValid()); 161 CHECK(format.IsValid());
162 *video_format = format;
98 } 163 }
99 164
100 // Reads and parses the header of a Y4M |file|, returning the collected pixel 165 FileVideoCaptureDevice::MjpegFileParser::MjpegFileParser(
101 // format in |video_format|. Returns the index of the first byte of the first 166 const base::FilePath& file_path)
102 // video frame. 167 : VideoFileParser(file_path) {}
103 // Restrictions: Only trivial per-frame headers are supported.
104 // static
105 int64 FileVideoCaptureDevice::ParseFileAndExtractVideoFormat(
106 base::File* file,
107 media::VideoCaptureFormat* video_format) {
108 std::string header(kY4MHeaderMaxSize, 0);
109 file->Read(0, &header[0], kY4MHeaderMaxSize - 1);
110 168
111 size_t header_end = header.find(kY4MSimpleFrameDelimiter); 169 FileVideoCaptureDevice::MjpegFileParser::~MjpegFileParser() {}
112 CHECK_NE(header_end, header.npos);
113 170
114 ParseY4MTags(header, video_format); 171 bool FileVideoCaptureDevice::MjpegFileParser::Initialize(
115 return header_end + kY4MSimpleFrameDelimiterSize; 172 media::VideoCaptureFormat* capture_format) {
173 mapped_file_.reset(new base::MemoryMappedFile());
174
175 if (!mapped_file_->Initialize(file_path_) || !mapped_file_->IsValid()) {
176 LOG(ERROR) << "File memory map error: " << file_path_.value();
177 return false;
178 }
179
180 JpegParseResult result;
181 if (!ParseJpegPicture(mapped_file_->data(), mapped_file_->length(), &result))
182 return false;
183
184 frame_size_ = result.image_size;
185 if (frame_size_ > static_cast<int>(mapped_file_->length())) {
186 LOG(ERROR) << "File is incomplete";
187 return false;
188 }
189
190 VideoCaptureFormat format;
191 format.pixel_format = media::VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG;
192 format.frame_size.set_width(result.frame_header.visible_width);
193 format.frame_size.set_height(result.frame_header.visible_height);
194 format.frame_rate = kMJpegFrameRate;
195 if (!format.IsValid())
196 return false;
197 *capture_format = format;
198 return true;
116 } 199 }
117 200
118 // Opens a given file for reading, and returns the file to the caller, who is 201 const uint8_t* FileVideoCaptureDevice::MjpegFileParser::GetNextFrame(
119 // responsible for closing it. 202 int* frame_size) {
203 const uint8_t* buf_ptr = mapped_file_->data() + current_byte_index_;
204
205 JpegParseResult result;
206 if (!ParseJpegPicture(buf_ptr, mapped_file_->length() - current_byte_index_,
207 &result)) {
208 return nullptr;
209 }
210 *frame_size = frame_size_ = result.image_size;
mcasas 2015/08/19 22:17:35 Should we DCHECK something of |result|? DCHECK_GT(
henryhsu 2015/08/20 03:18:57 We don't use result.data_size. I think if ParseJpe
211 current_byte_index_ += frame_size_;
212 // reset the pointer to play repeatedly.
mcasas 2015/08/19 22:17:34 s/reset/Reset/
henryhsu 2015/08/20 03:18:57 Done.
213 if (current_byte_index_ >= mapped_file_->length())
214 current_byte_index_ = first_frame_byte_index_;
215 return buf_ptr;
216 }
217
120 // static 218 // static
121 base::File FileVideoCaptureDevice::OpenFileForRead( 219 bool FileVideoCaptureDevice::GetVideoCaptureFormat(
122 const base::FilePath& file_path) { 220 const base::FilePath& file_path,
123 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); 221 media::VideoCaptureFormat* video_format) {
124 DLOG_IF(ERROR, file.IsValid()) 222 scoped_ptr<VideoFileParser> file_parser =
125 << file_path.value() 223 GetVideoFileParser(file_path, video_format);
mcasas 2015/08/19 22:17:34 Creating a VideoFileParser just for checking if th
henryhsu 2015/08/20 03:18:57 I move buffer allocation to GetNextFrame. Only all
126 << ", error: " << base::File::ErrorToString(file.error_details()); 224 if (!file_parser)
kcwu 2015/08/19 11:29:38 return file_parser != nullptr;
henryhsu 2015/08/20 03:18:57 Done.
127 return file.Pass(); 225 return false;
226 return true;
227 }
228
229 // static
230 scoped_ptr<FileVideoCaptureDevice::VideoFileParser>
231 FileVideoCaptureDevice::GetVideoFileParser(
232 const base::FilePath& file_path,
233 media::VideoCaptureFormat* video_format) {
234 scoped_ptr<VideoFileParser> file_parser;
235
236 if (base::EndsWith(file_path.value(), "y4m",
237 base::CompareCase::INSENSITIVE_ASCII)) {
238 file_parser.reset(new Y4mFileParser(file_path));
239 } else if (base::EndsWith(file_path.value(), "mjpeg",
240 base::CompareCase::INSENSITIVE_ASCII)) {
241 file_parser.reset(new MjpegFileParser(file_path));
242 } else {
243 LOG(ERROR) << "Unsupported file format.";
244 return file_parser.Pass();
245 }
246
247 if (!file_parser || !file_parser->Initialize(video_format)) {
248 file_parser.reset();
249 }
250 return file_parser.Pass();
128 } 251 }
129 252
130 FileVideoCaptureDevice::FileVideoCaptureDevice(const base::FilePath& file_path) 253 FileVideoCaptureDevice::FileVideoCaptureDevice(const base::FilePath& file_path)
131 : capture_thread_("CaptureThread"), 254 : capture_thread_("CaptureThread"), file_path_(file_path) {}
132 file_path_(file_path),
133 frame_size_(0),
134 current_byte_index_(0),
135 first_frame_byte_index_(0) {
136 }
137 255
138 FileVideoCaptureDevice::~FileVideoCaptureDevice() { 256 FileVideoCaptureDevice::~FileVideoCaptureDevice() {
139 DCHECK(thread_checker_.CalledOnValidThread()); 257 DCHECK(thread_checker_.CalledOnValidThread());
140 // Check if the thread is running. 258 // Check if the thread is running.
141 // This means that the device have not been DeAllocated properly. 259 // This means that the device have not been DeAllocated properly.
142 CHECK(!capture_thread_.IsRunning()); 260 CHECK(!capture_thread_.IsRunning());
143 } 261 }
144 262
145 void FileVideoCaptureDevice::AllocateAndStart( 263 void FileVideoCaptureDevice::AllocateAndStart(
146 const VideoCaptureParams& params, 264 const VideoCaptureParams& params,
(...skipping 11 matching lines...) Expand all
158 void FileVideoCaptureDevice::StopAndDeAllocate() { 276 void FileVideoCaptureDevice::StopAndDeAllocate() {
159 DCHECK(thread_checker_.CalledOnValidThread()); 277 DCHECK(thread_checker_.CalledOnValidThread());
160 CHECK(capture_thread_.IsRunning()); 278 CHECK(capture_thread_.IsRunning());
161 279
162 capture_thread_.message_loop()->PostTask( 280 capture_thread_.message_loop()->PostTask(
163 FROM_HERE, base::Bind(&FileVideoCaptureDevice::OnStopAndDeAllocate, 281 FROM_HERE, base::Bind(&FileVideoCaptureDevice::OnStopAndDeAllocate,
164 base::Unretained(this))); 282 base::Unretained(this)));
165 capture_thread_.Stop(); 283 capture_thread_.Stop();
166 } 284 }
167 285
168 int FileVideoCaptureDevice::CalculateFrameSize() const {
169 DCHECK_EQ(capture_format_.pixel_format, VIDEO_CAPTURE_PIXEL_FORMAT_I420);
170 DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
171 return capture_format_.ImageAllocationSize();
172 }
173
174 void FileVideoCaptureDevice::OnAllocateAndStart( 286 void FileVideoCaptureDevice::OnAllocateAndStart(
175 const VideoCaptureParams& params, 287 const VideoCaptureParams& params,
176 scoped_ptr<VideoCaptureDevice::Client> client) { 288 scoped_ptr<VideoCaptureDevice::Client> client) {
177 DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current()); 289 DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
178 290
179 client_ = client.Pass(); 291 client_ = client.Pass();
180 292
181 // Open the file and parse the header. Get frame size and format. 293 DCHECK(!file_parser_);
182 DCHECK(!file_.IsValid()); 294 file_parser_ = GetVideoFileParser(file_path_, &capture_format_);
183 file_ = OpenFileForRead(file_path_); 295 if (!file_parser_) {
184 if (!file_.IsValid()) {
185 client_->OnError("Could not open Video file"); 296 client_->OnError("Could not open Video file");
186 return; 297 return;
187 } 298 }
188 first_frame_byte_index_ = 299
189 ParseFileAndExtractVideoFormat(&file_, &capture_format_);
190 current_byte_index_ = first_frame_byte_index_;
191 DVLOG(1) << "Opened video file " << capture_format_.frame_size.ToString() 300 DVLOG(1) << "Opened video file " << capture_format_.frame_size.ToString()
192 << ", fps: " << capture_format_.frame_rate; 301 << ", fps: " << capture_format_.frame_rate;
193 302
194 frame_size_ = CalculateFrameSize();
195 video_frame_.reset(new uint8[frame_size_]);
196
197 capture_thread_.message_loop()->PostTask( 303 capture_thread_.message_loop()->PostTask(
198 FROM_HERE, base::Bind(&FileVideoCaptureDevice::OnCaptureTask, 304 FROM_HERE, base::Bind(&FileVideoCaptureDevice::OnCaptureTask,
199 base::Unretained(this))); 305 base::Unretained(this)));
200 } 306 }
201 307
202 void FileVideoCaptureDevice::OnStopAndDeAllocate() { 308 void FileVideoCaptureDevice::OnStopAndDeAllocate() {
203 DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current()); 309 DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
204 file_.Close(); 310 file_parser_.reset();
205 client_.reset(); 311 client_.reset();
206 current_byte_index_ = 0;
207 first_frame_byte_index_ = 0;
208 frame_size_ = 0;
209 next_frame_time_ = base::TimeTicks(); 312 next_frame_time_ = base::TimeTicks();
210 video_frame_.reset();
211 } 313 }
212 314
213 void FileVideoCaptureDevice::OnCaptureTask() { 315 void FileVideoCaptureDevice::OnCaptureTask() {
214 DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current()); 316 DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
215 if (!client_) 317 if (!client_)
216 return; 318 return;
217 int result =
218 file_.Read(current_byte_index_,
219 reinterpret_cast<char*>(video_frame_.get()), frame_size_);
220
221 // If we passed EOF to base::File, it will return 0 read characters. In that
222 // case, reset the pointer and read again.
223 if (result != frame_size_) {
224 CHECK_EQ(result, 0);
225 current_byte_index_ = first_frame_byte_index_;
226 CHECK_EQ(
227 file_.Read(current_byte_index_,
228 reinterpret_cast<char*>(video_frame_.get()), frame_size_),
229 frame_size_);
230 } else {
231 current_byte_index_ += frame_size_ + kY4MSimpleFrameDelimiterSize;
232 }
233 319
234 // Give the captured frame to the client. 320 // Give the captured frame to the client.
321 int frame_size = 0;
322 const uint8_t* frame_ptr = file_parser_->GetNextFrame(&frame_size);
323 CHECK(frame_ptr);
mcasas 2015/08/19 22:17:35 and DCHECK(frame_size); ? It might look like over
henryhsu 2015/08/20 03:18:57 Done.
235 const base::TimeTicks current_time = base::TimeTicks::Now(); 324 const base::TimeTicks current_time = base::TimeTicks::Now();
236 client_->OnIncomingCapturedData(video_frame_.get(), frame_size_, 325 client_->OnIncomingCapturedData(frame_ptr, frame_size, capture_format_, 0,
237 capture_format_, 0, current_time); 326 current_time);
238 // Reschedule next CaptureTask. 327 // Reschedule next CaptureTask.
239 const base::TimeDelta frame_interval = 328 const base::TimeDelta frame_interval =
240 base::TimeDelta::FromMicroseconds(1E6 / capture_format_.frame_rate); 329 base::TimeDelta::FromMicroseconds(1E6 / capture_format_.frame_rate);
241 if (next_frame_time_.is_null()) { 330 if (next_frame_time_.is_null()) {
242 next_frame_time_ = current_time + frame_interval; 331 next_frame_time_ = current_time + frame_interval;
243 } else { 332 } else {
244 next_frame_time_ += frame_interval; 333 next_frame_time_ += frame_interval;
245 // Don't accumulate any debt if we are lagging behind - just post next frame 334 // Don't accumulate any debt if we are lagging behind - just post next frame
246 // immediately and continue as normal. 335 // immediately and continue as normal.
247 if (next_frame_time_ < current_time) 336 if (next_frame_time_ < current_time)
248 next_frame_time_ = current_time; 337 next_frame_time_ = current_time;
249 } 338 }
250 base::MessageLoop::current()->PostDelayedTask( 339 base::MessageLoop::current()->PostDelayedTask(
251 FROM_HERE, base::Bind(&FileVideoCaptureDevice::OnCaptureTask, 340 FROM_HERE, base::Bind(&FileVideoCaptureDevice::OnCaptureTask,
252 base::Unretained(this)), 341 base::Unretained(this)),
253 next_frame_time_ - current_time); 342 next_frame_time_ - current_time);
254 } 343 }
255 344
256 } // namespace media 345 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698