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

Side by Side Diff: media/video/capture/mac/video_capture_device_avfoundation_mac.mm

Issue 846743003: Revert "Mac Video Capture: Change pixel format preference for AVFoundation" Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 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
« no previous file with comments | « media/base/mac/coremedia_glue.h ('k') | media/video/capture/mac/video_capture_device_mac.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #import "media/video/capture/mac/video_capture_device_avfoundation_mac.h" 5 #import "media/video/capture/mac/video_capture_device_avfoundation_mac.h"
6 6
7 #import <CoreVideo/CoreVideo.h> 7 #import <CoreVideo/CoreVideo.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/mac/foundation_util.h" 10 #include "base/mac/foundation_util.h"
11 #include "media/video/capture/mac/video_capture_device_mac.h" 11 #include "media/video/capture/mac/video_capture_device_mac.h"
12 #include "ui/gfx/geometry/size.h" 12 #include "ui/gfx/geometry/size.h"
13 13
14 // Prefer MJPEG if frame width or height is larger than this.
15 static const int kMjpegWidthThreshold = 640;
16 static const int kMjpegHeightThreshold = 480;
17
18 // This function translates Mac Core Video pixel formats to Chromium pixel
19 // formats. Chromium pixel formats are sorted in order of preference.
20 media::VideoPixelFormat FourCCToChromiumPixelFormat(FourCharCode code) {
21 switch (code) {
22 case kCVPixelFormatType_422YpCbCr8:
23 return media::PIXEL_FORMAT_UYVY;
24 case CoreMediaGlue::kCMPixelFormat_422YpCbCr8_yuvs:
25 return media::PIXEL_FORMAT_YUY2;
26 case CoreMediaGlue::kCMVideoCodecType_JPEG_OpenDML:
27 return media::PIXEL_FORMAT_MJPEG;
28 case CoreMediaGlue::kCMPixelFormat_420YpCbCr8BiPlanarVideoRange:
29 return media::PIXEL_FORMAT_NV12;
30 default:
31 return media::PIXEL_FORMAT_UNKNOWN;
32 }
33 }
34
35 @implementation VideoCaptureDeviceAVFoundation 14 @implementation VideoCaptureDeviceAVFoundation
36 15
37 #pragma mark Class methods 16 #pragma mark Class methods
38 17
39 + (void)getDeviceNames:(NSMutableDictionary*)deviceNames { 18 + (void)getDeviceNames:(NSMutableDictionary*)deviceNames {
40 // At this stage we already know that AVFoundation is supported and the whole 19 // At this stage we already know that AVFoundation is supported and the whole
41 // library is loaded and initialised, by the device monitoring. 20 // library is loaded and initialised, by the device monitoring.
42 NSArray* devices = [AVCaptureDeviceGlue devices]; 21 NSArray* devices = [AVCaptureDeviceGlue devices];
43 for (CrAVCaptureDevice* device in devices) { 22 for (CrAVCaptureDevice* device in devices) {
44 if (([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()] || 23 if (([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()] ||
(...skipping 24 matching lines...) Expand all
69 CrAVCaptureDevice* device = nil; 48 CrAVCaptureDevice* device = nil;
70 for (device in devices) { 49 for (device in devices) {
71 if ([[device uniqueID] UTF8String] == name.id()) 50 if ([[device uniqueID] UTF8String] == name.id())
72 break; 51 break;
73 } 52 }
74 if (device == nil) 53 if (device == nil)
75 return; 54 return;
76 for (CrAVCaptureDeviceFormat* format in device.formats) { 55 for (CrAVCaptureDeviceFormat* format in device.formats) {
77 // MediaSubType is a CMPixelFormatType but can be used as CVPixelFormatType 56 // MediaSubType is a CMPixelFormatType but can be used as CVPixelFormatType
78 // as well according to CMFormatDescription.h 57 // as well according to CMFormatDescription.h
79 const media::VideoPixelFormat pixelFormat = FourCCToChromiumPixelFormat( 58 media::VideoPixelFormat pixelFormat = media::PIXEL_FORMAT_UNKNOWN;
80 CoreMediaGlue::CMFormatDescriptionGetMediaSubType( 59 switch (CoreMediaGlue::CMFormatDescriptionGetMediaSubType(
81 [format formatDescription])); 60 [format formatDescription])) {
61 case kCVPixelFormatType_422YpCbCr8: // Typical.
62 pixelFormat = media::PIXEL_FORMAT_UYVY;
63 break;
64 case CoreMediaGlue::kCMPixelFormat_422YpCbCr8_yuvs:
65 pixelFormat = media::PIXEL_FORMAT_YUY2;
66 break;
67 case CoreMediaGlue::kCMVideoCodecType_JPEG_OpenDML:
68 pixelFormat = media::PIXEL_FORMAT_MJPEG;
69 default:
70 break;
71 }
82 72
83 CoreMediaGlue::CMVideoDimensions dimensions = 73 CoreMediaGlue::CMVideoDimensions dimensions =
84 CoreMediaGlue::CMVideoFormatDescriptionGetDimensions( 74 CoreMediaGlue::CMVideoFormatDescriptionGetDimensions(
85 [format formatDescription]); 75 [format formatDescription]);
86 76
87 for (CrAVFrameRateRange* frameRate in 77 for (CrAVFrameRateRange* frameRate in
88 [format videoSupportedFrameRateRanges]) { 78 [format videoSupportedFrameRateRanges]) {
89 media::VideoCaptureFormat format( 79 media::VideoCaptureFormat format(
90 gfx::Size(dimensions.width, dimensions.height), 80 gfx::Size(dimensions.width, dimensions.height),
91 frameRate.maxFrameRate, 81 frameRate.maxFrameRate,
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 // VideoCaptureDeviceMac::ReceiveFrame() is calling here, depending on the 176 // VideoCaptureDeviceMac::ReceiveFrame() is calling here, depending on the
187 // running state. VCDM::ReceiveFrame() calls here to change aspect ratio. 177 // running state. VCDM::ReceiveFrame() calls here to change aspect ratio.
188 DCHECK((![captureSession_ isRunning] && 178 DCHECK((![captureSession_ isRunning] &&
189 main_thread_checker_.CalledOnValidThread()) || 179 main_thread_checker_.CalledOnValidThread()) ||
190 callback_thread_checker_.CalledOnValidThread()); 180 callback_thread_checker_.CalledOnValidThread());
191 181
192 frameWidth_ = width; 182 frameWidth_ = width;
193 frameHeight_ = height; 183 frameHeight_ = height;
194 frameRate_ = frameRate; 184 frameRate_ = frameRate;
195 185
196 FourCharCode best_fourcc = kCVPixelFormatType_422YpCbCr8;
197 const bool prefer_mjpeg =
198 width > kMjpegWidthThreshold || height > kMjpegHeightThreshold;
199 for (CrAVCaptureDeviceFormat* format in captureDevice_.formats) {
200 const FourCharCode fourcc =
201 CoreMediaGlue::CMFormatDescriptionGetMediaSubType(
202 [format formatDescription]);
203 if (prefer_mjpeg &&
204 fourcc == CoreMediaGlue::kCMVideoCodecType_JPEG_OpenDML) {
205 best_fourcc = fourcc;
206 break;
207 }
208 // Compare according to Chromium preference.
209 if (FourCCToChromiumPixelFormat(fourcc) <
210 FourCCToChromiumPixelFormat(best_fourcc)) {
211 best_fourcc = fourcc;
212 }
213 }
214
215 // The capture output has to be configured, despite Mac documentation 186 // The capture output has to be configured, despite Mac documentation
216 // detailing that setting the sessionPreset would be enough. The reason for 187 // detailing that setting the sessionPreset would be enough. The reason for
217 // this mismatch is probably because most of the AVFoundation docs are written 188 // this mismatch is probably because most of the AVFoundation docs are written
218 // for iOS and not for MacOsX. AVVideoScalingModeKey() refers to letterboxing 189 // for iOS and not for MacOsX. AVVideoScalingModeKey() refers to letterboxing
219 // yes/no and preserve aspect ratio yes/no when scaling. Currently we set 190 // yes/no and preserve aspect ratio yes/no when scaling. Currently we set
220 // cropping and preservation. 191 // cropping and preservation.
221 NSDictionary* videoSettingsDictionary = @{ 192 NSDictionary* videoSettingsDictionary = @{
222 (id)kCVPixelBufferWidthKey : @(width), 193 (id)kCVPixelBufferWidthKey : @(width),
223 (id)kCVPixelBufferHeightKey : @(height), 194 (id)kCVPixelBufferHeightKey : @(height),
224 (id)kCVPixelBufferPixelFormatTypeKey : @(best_fourcc), 195 (id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_422YpCbCr8),
225 AVFoundationGlue::AVVideoScalingModeKey() : 196 AVFoundationGlue::AVVideoScalingModeKey() :
226 AVFoundationGlue::AVVideoScalingModeResizeAspectFill() 197 AVFoundationGlue::AVVideoScalingModeResizeAspectFill()
227 }; 198 };
228 [captureVideoDataOutput_ setVideoSettings:videoSettingsDictionary]; 199 [captureVideoDataOutput_ setVideoSettings:videoSettingsDictionary];
229 200
230 CrAVCaptureConnection* captureConnection = [captureVideoDataOutput_ 201 CrAVCaptureConnection* captureConnection = [captureVideoDataOutput_
231 connectionWithMediaType:AVFoundationGlue::AVMediaTypeVideo()]; 202 connectionWithMediaType:AVFoundationGlue::AVMediaTypeVideo()];
232 // Check selector existence, related to bugs http://crbug.com/327532 and 203 // Check selector existence, related to bugs http://crbug.com/327532 and
233 // http://crbug.com/328096. 204 // http://crbug.com/328096.
234 // CMTimeMake accepts integer argumenst but |frameRate| is float, round it. 205 // CMTimeMake accepts integer argumenst but |frameRate| is float, round it.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 #pragma mark Private methods 246 #pragma mark Private methods
276 247
277 // |captureOutput| is called by the capture device to deliver a new frame. 248 // |captureOutput| is called by the capture device to deliver a new frame.
278 - (void)captureOutput:(CrAVCaptureOutput*)captureOutput 249 - (void)captureOutput:(CrAVCaptureOutput*)captureOutput
279 didOutputSampleBuffer:(CoreMediaGlue::CMSampleBufferRef)sampleBuffer 250 didOutputSampleBuffer:(CoreMediaGlue::CMSampleBufferRef)sampleBuffer
280 fromConnection:(CrAVCaptureConnection*)connection { 251 fromConnection:(CrAVCaptureConnection*)connection {
281 // AVFoundation calls from a number of threads, depending on, at least, if 252 // AVFoundation calls from a number of threads, depending on, at least, if
282 // Chrome is on foreground or background. Sample the actual thread here. 253 // Chrome is on foreground or background. Sample the actual thread here.
283 callback_thread_checker_.DetachFromThread(); 254 callback_thread_checker_.DetachFromThread();
284 callback_thread_checker_.CalledOnValidThread(); 255 callback_thread_checker_.CalledOnValidThread();
256 CVImageBufferRef videoFrame =
257 CoreMediaGlue::CMSampleBufferGetImageBuffer(sampleBuffer);
258 // Lock the frame and calculate frame size.
259 const int kLockFlags = kCVPixelBufferLock_ReadOnly;
260 if (CVPixelBufferLockBaseAddress(videoFrame, kLockFlags) ==
261 kCVReturnSuccess) {
262 void* baseAddress = CVPixelBufferGetBaseAddress(videoFrame);
263 size_t bytesPerRow = CVPixelBufferGetBytesPerRow(videoFrame);
264 size_t frameWidth = CVPixelBufferGetWidth(videoFrame);
265 size_t frameHeight = CVPixelBufferGetHeight(videoFrame);
266 size_t frameSize = bytesPerRow * frameHeight;
267 UInt8* addressToPass = reinterpret_cast<UInt8*>(baseAddress);
285 268
286 const CoreMediaGlue::CMFormatDescriptionRef formatDescription = 269 media::VideoCaptureFormat captureFormat(
287 CoreMediaGlue::CMSampleBufferGetFormatDescription(sampleBuffer); 270 gfx::Size(frameWidth, frameHeight),
288 const FourCharCode fourcc = 271 frameRate_,
289 CoreMediaGlue::CMFormatDescriptionGetMediaSubType(formatDescription); 272 media::PIXEL_FORMAT_UYVY);
290 const CoreMediaGlue::CMVideoDimensions dimensions = 273 {
291 CoreMediaGlue::CMVideoFormatDescriptionGetDimensions(formatDescription); 274 base::AutoLock lock(lock_);
292 const media::VideoCaptureFormat captureFormat( 275 if (frameReceiver_) {
293 gfx::Size(dimensions.width, dimensions.height), 276 frameReceiver_->ReceiveFrame(
294 frameRate_, 277 addressToPass, frameSize, captureFormat, 0, 0);
295 FourCCToChromiumPixelFormat(fourcc)); 278 }
279 }
296 280
297 char* baseAddress = 0; 281 CVPixelBufferUnlockBaseAddress(videoFrame, kLockFlags);
298 size_t frameSize = 0;
299 CVImageBufferRef videoFrame = nil;
300 if (fourcc == CoreMediaGlue::kCMVideoCodecType_JPEG_OpenDML) {
301 // If MJPEG, use block buffer instead of pixel buffer.
302 CoreMediaGlue::CMBlockBufferRef blockBuffer =
303 CoreMediaGlue::CMSampleBufferGetDataBuffer(sampleBuffer);
304 if (CoreMediaGlue::CMBlockBufferGetDataLength(blockBuffer) > 0) {
305 size_t length;
306 CoreMediaGlue::CMBlockBufferGetDataPointer(blockBuffer, 0, &length,
307 &frameSize,
308 &baseAddress);
309 }
310 } else {
311 videoFrame = CoreMediaGlue::CMSampleBufferGetImageBuffer(sampleBuffer);
312 // Lock the frame and calculate frame size.
313 if (CVPixelBufferLockBaseAddress(videoFrame, kCVPixelBufferLock_ReadOnly) ==
314 kCVReturnSuccess) {
315 baseAddress = static_cast<char*>(CVPixelBufferGetBaseAddress(videoFrame));
316 frameSize = CVPixelBufferGetHeight(videoFrame) *
317 CVPixelBufferGetBytesPerRow(videoFrame);
318 } else {
319 videoFrame = nil;
320 }
321 } 282 }
322
323 {
324 base::AutoLock lock(lock_);
325 if (frameReceiver_ && baseAddress) {
326 frameReceiver_->ReceiveFrame(reinterpret_cast<uint8_t*>(baseAddress),
327 frameSize, captureFormat, 0, 0);
328 }
329 }
330
331 if (videoFrame)
332 CVPixelBufferUnlockBaseAddress(videoFrame, kCVPixelBufferLock_ReadOnly);
333 } 283 }
334 284
335 - (void)onVideoError:(NSNotification*)errorNotification { 285 - (void)onVideoError:(NSNotification*)errorNotification {
336 NSError* error = base::mac::ObjCCast<NSError>([[errorNotification userInfo] 286 NSError* error = base::mac::ObjCCast<NSError>([[errorNotification userInfo]
337 objectForKey:AVFoundationGlue::AVCaptureSessionErrorKey()]); 287 objectForKey:AVFoundationGlue::AVCaptureSessionErrorKey()]);
338 [self sendErrorString:[NSString 288 [self sendErrorString:[NSString
339 stringWithFormat:@"%@: %@", 289 stringWithFormat:@"%@: %@",
340 [error localizedDescription], 290 [error localizedDescription],
341 [error localizedFailureReason]]]; 291 [error localizedFailureReason]]];
342 } 292 }
343 293
344 - (void)sendErrorString:(NSString*)error { 294 - (void)sendErrorString:(NSString*)error {
345 DLOG(ERROR) << [error UTF8String]; 295 DLOG(ERROR) << [error UTF8String];
346 base::AutoLock lock(lock_); 296 base::AutoLock lock(lock_);
347 if (frameReceiver_) 297 if (frameReceiver_)
348 frameReceiver_->ReceiveError([error UTF8String]); 298 frameReceiver_->ReceiveError([error UTF8String]);
349 } 299 }
350 300
351 @end 301 @end
OLDNEW
« no previous file with comments | « media/base/mac/coremedia_glue.h ('k') | media/video/capture/mac/video_capture_device_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698