AVFoundationVideoCapturer: Output native frames instead of I420 frames
BUG=webrtc:4081 Review-Url: https://codereview.webrtc.org/2135953002 Cr-Commit-Position: refs/heads/master@{#13478}
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
include_rules = [
|
include_rules = [
|
||||||
"+WebRTC",
|
"+WebRTC",
|
||||||
"+webrtc/api",
|
"+webrtc/api",
|
||||||
|
"+webrtc/common_video/include",
|
||||||
"+webrtc/media",
|
"+webrtc/media",
|
||||||
"+webrtc/system_wrappers",
|
"+webrtc/system_wrappers",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#import <AVFoundation/AVFoundation.h>
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
|
||||||
|
#include "webrtc/common_video/include/i420_buffer_pool.h"
|
||||||
#include "webrtc/media/base/videocapturer.h"
|
#include "webrtc/media/base/videocapturer.h"
|
||||||
#include "webrtc/video_frame.h"
|
#include "webrtc/video_frame.h"
|
||||||
|
|
||||||
@ -61,10 +62,11 @@ class AVFoundationVideoCapturer : public cricket::VideoCapturer,
|
|||||||
void OnMessage(rtc::Message *msg) override;
|
void OnMessage(rtc::Message *msg) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnFrameMessage(CVImageBufferRef image_buffer, int64_t capture_time);
|
void OnFrameMessage(CVImageBufferRef image_buffer, int64_t capture_time_ns);
|
||||||
|
|
||||||
RTCAVFoundationVideoCapturerInternal *_capturer;
|
RTCAVFoundationVideoCapturerInternal *_capturer;
|
||||||
rtc::Thread *_startThread; // Set in Start(), unset in Stop().
|
rtc::Thread *_startThread; // Set in Start(), unset in Stop().
|
||||||
|
webrtc::I420BufferPool _buffer_pool;
|
||||||
}; // AVFoundationVideoCapturer
|
}; // AVFoundationVideoCapturer
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
#include "webrtc/base/bind.h"
|
#include "webrtc/base/bind.h"
|
||||||
#include "webrtc/base/checks.h"
|
#include "webrtc/base/checks.h"
|
||||||
#include "webrtc/base/thread.h"
|
#include "webrtc/base/thread.h"
|
||||||
|
#include "webrtc/common_video/include/corevideo_frame_buffer.h"
|
||||||
|
|
||||||
// TODO(tkchin): support other formats.
|
// TODO(tkchin): support other formats.
|
||||||
static NSString *const kDefaultPreset = AVCaptureSessionPreset640x480;
|
static NSString *const kDefaultPreset = AVCaptureSessionPreset640x480;
|
||||||
@ -642,57 +643,46 @@ void AVFoundationVideoCapturer::OnMessage(rtc::Message *msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AVFoundationVideoCapturer::OnFrameMessage(CVImageBufferRef image_buffer,
|
void AVFoundationVideoCapturer::OnFrameMessage(CVImageBufferRef image_buffer,
|
||||||
int64_t capture_time) {
|
int64_t capture_time_ns) {
|
||||||
RTC_DCHECK(_startThread->IsCurrent());
|
RTC_DCHECK(_startThread->IsCurrent());
|
||||||
|
|
||||||
// Base address must be unlocked to access frame data.
|
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer =
|
||||||
CVOptionFlags lock_flags = kCVPixelBufferLock_ReadOnly;
|
new rtc::RefCountedObject<webrtc::CoreVideoFrameBuffer>(image_buffer);
|
||||||
CVReturn ret = CVPixelBufferLockBaseAddress(image_buffer, lock_flags);
|
|
||||||
if (ret != kCVReturnSuccess) {
|
const int captured_width = buffer->width();
|
||||||
|
const int captured_height = buffer->height();
|
||||||
|
|
||||||
|
int adapted_width;
|
||||||
|
int adapted_height;
|
||||||
|
int crop_width;
|
||||||
|
int crop_height;
|
||||||
|
int crop_x;
|
||||||
|
int crop_y;
|
||||||
|
int64_t translated_camera_time_us;
|
||||||
|
|
||||||
|
if (!AdaptFrame(captured_width, captured_height,
|
||||||
|
capture_time_ns / rtc::kNumNanosecsPerMicrosec,
|
||||||
|
rtc::TimeMicros(), &adapted_width, &adapted_height,
|
||||||
|
&crop_width, &crop_height, &crop_x, &crop_y,
|
||||||
|
&translated_camera_time_us)) {
|
||||||
|
CVBufferRelease(image_buffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t const kYPlaneIndex = 0;
|
if (adapted_width != captured_width || crop_width != captured_width ||
|
||||||
static size_t const kUVPlaneIndex = 1;
|
adapted_height != captured_height || crop_height != captured_height) {
|
||||||
uint8_t* y_plane_address =
|
// TODO(magjed): Avoid converting to I420.
|
||||||
static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(image_buffer,
|
rtc::scoped_refptr<webrtc::I420Buffer> scaled_buffer(
|
||||||
kYPlaneIndex));
|
_buffer_pool.CreateBuffer(adapted_width, adapted_height));
|
||||||
size_t y_plane_height =
|
scaled_buffer->CropAndScaleFrom(buffer->NativeToI420Buffer(), crop_x,
|
||||||
CVPixelBufferGetHeightOfPlane(image_buffer, kYPlaneIndex);
|
crop_y, crop_width, crop_height);
|
||||||
size_t y_plane_width =
|
buffer = scaled_buffer;
|
||||||
CVPixelBufferGetWidthOfPlane(image_buffer, kYPlaneIndex);
|
}
|
||||||
size_t y_plane_bytes_per_row =
|
|
||||||
CVPixelBufferGetBytesPerRowOfPlane(image_buffer, kYPlaneIndex);
|
|
||||||
size_t uv_plane_height =
|
|
||||||
CVPixelBufferGetHeightOfPlane(image_buffer, kUVPlaneIndex);
|
|
||||||
size_t uv_plane_bytes_per_row =
|
|
||||||
CVPixelBufferGetBytesPerRowOfPlane(image_buffer, kUVPlaneIndex);
|
|
||||||
size_t frame_size = y_plane_bytes_per_row * y_plane_height +
|
|
||||||
uv_plane_bytes_per_row * uv_plane_height;
|
|
||||||
|
|
||||||
// Sanity check assumption that planar bytes are contiguous.
|
OnFrame(cricket::WebRtcVideoFrame(buffer, webrtc::kVideoRotation_0,
|
||||||
uint8_t* uv_plane_address =
|
translated_camera_time_us),
|
||||||
static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(image_buffer,
|
captured_width, captured_height);
|
||||||
kUVPlaneIndex));
|
|
||||||
RTC_DCHECK(uv_plane_address ==
|
|
||||||
y_plane_address + y_plane_height * y_plane_bytes_per_row);
|
|
||||||
|
|
||||||
// Stuff data into a cricket::CapturedFrame.
|
|
||||||
cricket::CapturedFrame frame;
|
|
||||||
frame.width = y_plane_width;
|
|
||||||
frame.height = y_plane_height;
|
|
||||||
frame.pixel_width = 1;
|
|
||||||
frame.pixel_height = 1;
|
|
||||||
frame.fourcc = static_cast<uint32_t>(cricket::FOURCC_NV12);
|
|
||||||
frame.time_stamp = capture_time;
|
|
||||||
frame.data = y_plane_address;
|
|
||||||
frame.data_size = frame_size;
|
|
||||||
|
|
||||||
// This will call a superclass method that will perform the frame conversion
|
|
||||||
// to I420.
|
|
||||||
SignalFrameCaptured(this, &frame);
|
|
||||||
|
|
||||||
CVPixelBufferUnlockBaseAddress(image_buffer, lock_flags);
|
|
||||||
CVBufferRelease(image_buffer);
|
CVBufferRelease(image_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user