Bug 1828450 - Revert 9aa28e73aaf8 - In VideoCaptureAvFoundation use MediaEvent to handle frames. r=webrtc-reviewers,ng

Differential Revision: https://phabricator.services.mozilla.com/D175656
This commit is contained in:
Andreas Pehrson 2023-04-21 08:58:00 +00:00
parent 32f66f3004
commit 85694e7eee
2 changed files with 60 additions and 37 deletions

View File

@ -11,25 +11,17 @@
#include "api/scoped_refptr.h"
#include "api/sequence_checker.h"
#include "MediaEventSource.h"
#include "modules/video_capture/video_capture_impl.h"
#include "mozilla/Maybe.h"
#include "PerformanceRecorder.h"
@interface VideoCaptureAdapter : NSObject <RTCVideoCapturerDelegate> {
@public
mozilla::MediaEventProducerExc<__strong RTCVideoFrame* _Nullable> frameEvent;
}
@end
@class VideoCaptureAdapter;
namespace webrtc::videocapturemodule {
/**
* VideoCaptureImpl implementation of the libwebrtc ios/mac sdk camera backend.
* Single threaded API. Callbacks run on the API thread.
*
* Internally callbacks come on a dedicated dispatch queue. We bounce them via a MediaEvent to the
* API thread.
* Single threaded except for OnFrame() that happens on a platform callback thread.
*/
class VideoCaptureAvFoundation : public VideoCaptureImpl {
public:
@ -42,16 +34,19 @@ class VideoCaptureAvFoundation : public VideoCaptureImpl {
// Starts capturing synchronously. Idempotent. If an existing capture is live and another
// capability is requested we'll restart the underlying backend with the new capability.
int32_t StartCapture(const VideoCaptureCapability& aCapability) override;
int32_t StartCapture(const VideoCaptureCapability& aCapability) MOZ_EXCLUDES(api_lock_) override;
// Stops capturing synchronously. Idempotent.
int32_t StopCapture() override;
bool CaptureStarted() override;
int32_t StopCapture() MOZ_EXCLUDES(api_lock_) override;
bool CaptureStarted() MOZ_EXCLUDES(api_lock_) override;
int32_t CaptureSettings(VideoCaptureCapability& aSettings) override;
// Callback on the mChecker thread.
void OnFrame(__strong RTCVideoFrame* _Nonnull aFrame);
// Callback. This can be called on any thread.
int32_t OnFrame(__strong RTCVideoFrame* _Nonnull aFrame) MOZ_EXCLUDES(api_lock_);
void SetTrackingId(uint32_t aTrackingIdProcId) override;
void SetTrackingId(uint32_t aTrackingIdProcId) MOZ_EXCLUDES(api_lock_) override;
// Registers the current thread with the profiler if not already registered.
void MaybeRegisterCallbackThread();
private:
// Control thread checker.
@ -59,21 +54,26 @@ class VideoCaptureAvFoundation : public VideoCaptureImpl {
AVCaptureDevice* _Nonnull const mDevice RTC_GUARDED_BY(mChecker);
VideoCaptureAdapter* _Nonnull const mAdapter RTC_GUARDED_BY(mChecker);
RTCCameraVideoCapturer* _Nonnull const mCapturer RTC_GUARDED_BY(mChecker);
// If capture has started, this is the capability it was started for.
mozilla::Maybe<VideoCaptureCapability> mCapability RTC_GUARDED_BY(mChecker);
// If capture has started, this is the capability it was started for. Written on the mChecker
// thread only.
mozilla::Maybe<VideoCaptureCapability> mCapability MOZ_GUARDED_BY(api_lock_);
// The image type that mCapability maps to. Set in lockstep with mCapability.
mozilla::Maybe<mozilla::CaptureStage::ImageType> mImageType RTC_GUARDED_BY(mChecker);
// Id string uniquely identifying this capture source.
mozilla::Maybe<mozilla::TrackingId> mTrackingId RTC_GUARDED_BY(mChecker);
// Handle for the mAdapter frame event. mChecker thread only.
mozilla::MediaEventListener mFrameListener RTC_GUARDED_BY(mChecker);
// Adds frame specific markers to the profiler while mTrackingId is set.
mozilla::PerformanceRecorderMulti<mozilla::CaptureStage> mCaptureRecorder
RTC_GUARDED_BY(mChecker);
mozilla::PerformanceRecorderMulti<mozilla::CopyVideoStage> mConversionRecorder
RTC_GUARDED_BY(mChecker);
mozilla::Maybe<mozilla::CaptureStage::ImageType> mImageType MOZ_GUARDED_BY(api_lock_);
// Id string uniquely identifying this capture source. Written on the mChecker thread only.
mozilla::Maybe<mozilla::TrackingId> mTrackingId MOZ_GUARDED_BY(api_lock_);
// Adds frame specific markers to the profiler while mTrackingId is set. Callback thread only.
mozilla::PerformanceRecorderMulti<mozilla::CaptureStage> mCaptureRecorder;
mozilla::PerformanceRecorderMulti<mozilla::CopyVideoStage> mConversionRecorder;
std::atomic<ProfilerThreadId> mCallbackThreadId;
};
} // namespace webrtc::videocapturemodule
@interface VideoCaptureAdapter : NSObject <RTCVideoCapturerDelegate> {
webrtc::Mutex _mutex;
webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable _capturer RTC_GUARDED_BY(_mutex);
}
- (void)setCapturer:(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer;
@end
#endif

View File

@ -73,9 +73,20 @@ AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
} // namespace
@implementation VideoCaptureAdapter
- (void)setCapturer:(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer {
webrtc::MutexLock lock(&_mutex);
_capturer = capturer;
}
- (void)capturer:(RTCVideoCapturer* _Nonnull)capturer
didCaptureVideoFrame:(RTCVideoFrame* _Nonnull)frame {
frameEvent.Notify(frame);
rtc::scoped_refptr<webrtc::videocapturemodule::VideoCaptureAvFoundation> cap;
{
webrtc::MutexLock lock(&_mutex);
cap = rtc::scoped_refptr(_capturer);
}
if (!cap) return;
cap->OnFrame(frame);
}
@end
@ -83,7 +94,8 @@ namespace webrtc::videocapturemodule {
VideoCaptureAvFoundation::VideoCaptureAvFoundation(AVCaptureDevice* _Nonnull aDevice)
: mDevice(aDevice),
mAdapter([[VideoCaptureAdapter alloc] init]),
mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc] initWithDelegate:mAdapter]) {
mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc] initWithDelegate:mAdapter]),
mCallbackThreadId() {
const char* uniqueId = [[aDevice uniqueID] UTF8String];
size_t len = strlen(uniqueId);
_deviceUniqueId = new (std::nothrow) char[len + 1];
@ -137,8 +149,7 @@ int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCa
}
}
mFrameListener = mAdapter->frameEvent.Connect(GetCurrentSerialEventTarget(), this,
&VideoCaptureAvFoundation::OnFrame);
[mAdapter setCapturer:this];
{
Monitor monitor("VideoCaptureAVFoundation::StartCapture");
@ -227,13 +238,14 @@ int32_t VideoCaptureAvFoundation::StopCapture() {
monitor.Wait();
}
mFrameListener.Disconnect();
[mAdapter setCapturer:nil];
return 0;
}
bool VideoCaptureAvFoundation::CaptureStarted() {
RTC_DCHECK_RUN_ON(&mChecker);
MutexLock lock(&api_lock_);
return mCapability.isSome();
}
@ -242,9 +254,9 @@ int32_t VideoCaptureAvFoundation::CaptureSettings(VideoCaptureCapability& aSetti
return -1;
}
void VideoCaptureAvFoundation::OnFrame(__strong RTCVideoFrame* _Nonnull aFrame) {
RTC_DCHECK_RUN_ON(&mChecker);
if (MOZ_LIKELY(mTrackingId)) {
int32_t VideoCaptureAvFoundation::OnFrame(__strong RTCVideoFrame* _Nonnull aFrame) {
MaybeRegisterCallbackThread();
if (MutexLock lock(&api_lock_); MOZ_LIKELY(mTrackingId)) {
mCaptureRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
aFrame.height, mImageType.valueOr(CaptureStage::ImageType::Unknown));
if (mCapability && mCapability->videoType != webrtc::VideoType::kI420) {
@ -266,12 +278,14 @@ void VideoCaptureAvFoundation::OnFrame(__strong RTCVideoFrame* _Nonnull aFrame)
.build();
MutexLock lock(&api_lock_);
DeliverCapturedFrame(frame);
int32_t rv = DeliverCapturedFrame(frame);
mCaptureRecorder.Record(0);
return rv;
}
void VideoCaptureAvFoundation::SetTrackingId(uint32_t aTrackingIdProcId) {
RTC_DCHECK_RUN_ON(&mChecker);
MutexLock lock(&api_lock_);
if (NS_WARN_IF(mTrackingId.isSome())) {
// This capture instance must be shared across multiple camera requests. For now ignore other
// requests than the first.
@ -279,4 +293,13 @@ void VideoCaptureAvFoundation::SetTrackingId(uint32_t aTrackingIdProcId) {
}
mTrackingId.emplace(TrackingId::Source::Camera, aTrackingIdProcId);
}
void VideoCaptureAvFoundation::MaybeRegisterCallbackThread() {
ProfilerThreadId id = profiler_current_thread_id();
if (MOZ_LIKELY(id == mCallbackThreadId)) {
return;
}
mCallbackThreadId = id;
CallbackThreadRegistry::Get()->Register(mCallbackThreadId, "VideoCaptureAVFoundationCallback");
}
} // namespace webrtc::videocapturemodule