From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 8647540300 for ; Wed, 19 Jan 2022 14:35:47 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3DE2868B0B4; Wed, 19 Jan 2022 16:35:45 +0200 (EET) Received: from mail-qv1-f54.google.com (mail-qv1-f54.google.com [209.85.219.54]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id DB16468AF50 for ; Wed, 19 Jan 2022 16:35:38 +0200 (EET) Received: by mail-qv1-f54.google.com with SMTP id c2so3022078qvw.3 for ; Wed, 19 Jan 2022 06:35:38 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:message-id:mime-version:subject:date :in-reply-to:cc:to:references; bh=sysdFl2pq+GPevBT7aSXG/zHNiTU/AXhxvQpxsJEM5o=; b=YGJ7yKPX/ceng69Sr9zoeiRXsgyYoxTAMzypzONjVOVjKHGPTc5gUw67/SC/fZMle7 rgPmkentUY+1HHEEtABOew+KJVmnZ3Rq3Qc1tb8KgJsZ7/mlZb813puAvrGtE8kZM/u9 xllNHVOvprFxtWHnv/DxV/Bsahg5Xc4FksPeuClRxVWrmfCmiI5QrbcWwOsnUxGtdPd2 UbvX8xV0BWr6D7+LOBCQxvx+4lPCoevaYOQ8paTHOymZrakPlaJCXbD7M3YtAff8sC0y zDWOqy+MrEoyf8hN7svqg9iDk3PXyzEiRaeIGbKkKAixKtgfqFQsoW+m2u2lk4sHc5ch ejyA== X-Gm-Message-State: AOAM531uFZo0QSqHzDFgtYbEiOiPMhLkVOAQOcpMoqCR8sf+S7+FxwqU fk46E8F5VwMn+I3UpAt7WUHeW7VKbINaSf8h X-Google-Smtp-Source: ABdhPJx4fgr9EwdMjLcXpUF8HCTI0ImJqsIrlP9qniuFXApXIFilE8vt7G7MhUqRiMvoZCdYaxegZQ== X-Received: by 2002:a05:6214:1c8a:: with SMTP id ib10mr27232524qvb.12.1642602937033; Wed, 19 Jan 2022 06:35:37 -0800 (PST) Received: from smtpclient.apple ([172.58.4.135]) by smtp.gmail.com with ESMTPSA id g22sm12312032qtk.23.2022.01.19.06.35.35 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Jan 2022 06:35:35 -0800 (PST) From: Romain Beauxis Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_D30E3475-BFBB-437F-9BA6-6B47CF86A6B9" Mime-Version: 1.0 (Mac OS X Mail 15.0 \(3693.40.0.1.81\)) Date: Wed, 19 Jan 2022 08:35:33 -0600 In-Reply-To: To: FFmpeg development discussions and patches References: X-Mailer: Apple Mail (2.3693.40.0.1.81) Subject: [FFmpeg-devel] [PATCH 2/5] libavdevice/avfoundation.m: Replace mutex-based concurrency by a thread-safe fifo queue with maximum length X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Thilo Borgmann , Marvin Scholz Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: --Apple-Mail=_D30E3475-BFBB-437F-9BA6-6B47CF86A6B9 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii The existing implementation of avdevice input has issues in its = concurrent model as it only allows for one shared frame between writing = and reading threads. This means that, if reading thread gets late, = frames get dropped, resulting in corrupted input. This patch changes the concurrency logic to use a single shared queue = for both video and audio frames. Previous version of the patch used = separate queues for audio and video but this could cause synchronization = issues. In order to avoid dropping initial audio frames, the video configuration = logic is also changed to assume height/width as configured when opening = the input device so as to not depend on the first video frame for it. --Apple-Mail=_D30E3475-BFBB-437F-9BA6-6B47CF86A6B9 Content-Disposition: attachment; filename=0001-libavdevice-avfoundation.m-Replace-mutex-based-concurr.eml Content-Type: message/rfc822; x-unix-mode=0644; name="0001-libavdevice-avfoundation.m-Replace-mutex-based-concurr.eml" Content-Transfer-Encoding: quoted-printable =46rom=20d1a4c6e74ff589d9e59e1310a9afc9bc185382a1=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Romain=20Beauxis=20=0A= Date:=20Sun,=2012=20Dec=202021=2017:29:27=20-0600=0ASubject:=20[PATCH]=20= libavdevice/avfoundation.m:=20Replace=20mutex-based=20concurrency=0A=20= handling=20in=20avfoundation.m=20by=20a=20thread-safe=20fifo=20queue=20= with=20maximum=20length=0AX-Unsent:=201=0ATo:=20ffmpeg-devel@ffmpeg.org=0A= =0A*=20Use=20a=20shared=20CMSimpleQueueEnqueue=20with=20maximum=20length=20= to=20queue=20and=20process=20incoming=20audio=20and=20video=20frames.=0A= *=20Simplify=20video=20configuration=20to=20avoid=20consuming=20first=20= frame.=0A*=20Log=20avfoundation=20errors.=0A*=20Use=20AVERROR_EXTERNAL=20= instead=20of=20AVERROR(EIO)=20in=20avfoundation=20errors.=0A=0A= Signed-off-by:=20Romain=20Beauxis=20=0A---=0A=20= libavdevice/avfoundation.m=20|=20227=20= +++++++++++++++++--------------------=0A=201=20file=20changed,=20101=20= insertions(+),=20126=20deletions(-)=0A=0Adiff=20--git=20= a/libavdevice/avfoundation.m=20b/libavdevice/avfoundation.m=0Aindex=20= 77c6e68763..e6f64b35b8=20100644=0A---=20a/libavdevice/avfoundation.m=0A= +++=20b/libavdevice/avfoundation.m=0A@@=20-26,7=20+26,7=20@@=0A=20=20*/=0A= =20=0A=20#import=20=0A-#include=20= =0A+#import=20=0A=20=0A=20#include=20= "libavutil/channel_layout.h"=0A=20#include=20"libavutil/pixdesc.h"=0A@@=20= -39,6=20+39,13=20@@=0A=20#include=20"libavutil/imgutils.h"=0A=20#include=20= "avdevice.h"=0A=20=0A+static=20void=20av_log_avfoundation(void=20*s,=20= int=20lvl,=20const=20char=20*str,=20OSStatus=20err)=20{=0A+=20=20=20=20= NSAutoreleasePool=20*pool=20=3D=20[[NSAutoreleasePool=20alloc]=20init];=0A= +=20=20=20=20av_log(s,=20lvl,=20"AVFoundation:=20%s,=20%s\n",=20str,=0A+=20= =20=20=20=20=20=20=20[[[NSError=20errorWithDomain:NSOSStatusErrorDomain=20= code:err=20userInfo:nil]=20localizedDescription]=20UTF8String]);=0A+=20=20= =20=20[pool=20release];=0A+}=0A+=0A=20static=20const=20int=20= avf_time_base=20=3D=201000000;=0A=20=0A=20static=20const=20AVRational=20= avf_time_base_q=20=3D=20{=0A@@=20-84,9=20+91,6=20@@=0A=20{=0A=20=20=20=20= =20AVClass*=20=20=20=20=20=20=20=20class;=0A=20=0A-=20=20=20=20int=20=20=20= =20=20=20=20=20=20=20=20=20=20frames_captured;=0A-=20=20=20=20int=20=20=20= =20=20=20=20=20=20=20=20=20=20audio_frames_captured;=0A-=20=20=20=20= pthread_mutex_t=20frame_lock;=0A=20=20=20=20=20id=20=20=20=20=20=20=20=20= =20=20=20=20=20=20avf_delegate;=0A=20=20=20=20=20id=20=20=20=20=20=20=20=20= =20=20=20=20=20=20avf_audio_delegate;=0A=20=0A@@=20-121,8=20+125,9=20@@=0A= =20=20=20=20=20AVCaptureSession=20=20=20=20=20=20=20=20=20= *capture_session;=0A=20=20=20=20=20AVCaptureVideoDataOutput=20= *video_output;=0A=20=20=20=20=20AVCaptureAudioDataOutput=20= *audio_output;=0A-=20=20=20=20CMSampleBufferRef=20=20=20=20=20=20=20=20=20= current_frame;=0A-=20=20=20=20CMSampleBufferRef=20=20=20=20=20=20=20=20=20= current_audio_frame;=0A+=0A+=20=20=20=20CMSimpleQueueRef=20=20=20=20=20=20= =20=20=20=20frames_queue;=0A+=20=20=20=20int=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20max_frames;=0A=20=0A=20=20=20=20=20= AVCaptureDevice=20=20=20=20=20=20=20=20=20=20*observed_device;=0A=20#if=20= !TARGET_OS_IPHONE=20&&=20__MAC_OS_X_VERSION_MIN_REQUIRED=20>=3D=201070=0A= @@=20-131,16=20+136,6=20@@=0A=20=20=20=20=20int=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20observed_quit;=0A=20}=20= AVFContext;=0A=20=0A-static=20void=20lock_frames(AVFContext*=20ctx)=0A-{=0A= -=20=20=20=20pthread_mutex_lock(&ctx->frame_lock);=0A-}=0A-=0A-static=20= void=20unlock_frames(AVFContext*=20ctx)=0A-{=0A-=20=20=20=20= pthread_mutex_unlock(&ctx->frame_lock);=0A-}=0A-=0A=20/**=20= FrameReciever=20class=20-=20delegate=20for=20AVCaptureSession=0A=20=20*/=0A= =20@interface=20AVFFrameReceiver=20:=20NSObject=0A@@=20-218,17=20+213,13=20= @@=20-=20(void)=20=20captureOutput:(AVCaptureOutput=20*)captureOutput=0A=20= =20=20didOutputSampleBuffer:(CMSampleBufferRef)videoFrame=0A=20=20=20=20=20= =20=20=20=20=20fromConnection:(AVCaptureConnection=20*)connection=0A=20{=0A= -=20=20=20=20lock_frames(_context);=0A+=20=20=20=20OSStatus=20ret=20=3D=20= CMSimpleQueueEnqueue(_context->frames_queue,=20videoFrame);=0A=20=0A-=20=20= =20=20if=20(_context->current_frame=20!=3D=20nil)=20{=0A-=20=20=20=20=20=20= =20=20CFRelease(_context->current_frame);=0A+=20=20=20=20if=20(ret=20!=3D=20= noErr)=20{=0A+=20=20=20=20=20=20av_log_avfoundation(_context,=20= AV_LOG_DEBUG,=20"Error=20while=20queueing=20video=20frame",=20ret);=0A=20= =20=20=20=20}=0A=20=0A-=20=20=20=20_context->current_frame=20=3D=20= (CMSampleBufferRef)CFRetain(videoFrame);=0A-=0A-=20=20=20=20= unlock_frames(_context);=0A-=0A-=20=20=20=20++_context->frames_captured;=0A= +=20=20=20=20CFRetain(videoFrame);=0A=20}=0A=20=0A=20@end=0A@@=20-262,17=20= +253,13=20@@=20-=20(void)=20=20captureOutput:(AVCaptureOutput=20= *)captureOutput=0A=20=20=20= didOutputSampleBuffer:(CMSampleBufferRef)audioFrame=0A=20=20=20=20=20=20=20= =20=20=20fromConnection:(AVCaptureConnection=20*)connection=0A=20{=0A-=20= =20=20=20lock_frames(_context);=0A+=20=20=20=20OSStatus=20ret=20=3D=20= CMSimpleQueueEnqueue(_context->frames_queue,=20audioFrame);=0A=20=0A-=20=20= =20=20if=20(_context->current_audio_frame=20!=3D=20nil)=20{=0A-=20=20=20=20= =20=20=20=20CFRelease(_context->current_audio_frame);=0A+=20=20=20=20if=20= (ret=20!=3D=20noErr)=20{=0A+=20=20=20=20=20=20= av_log_avfoundation(_context,=20AV_LOG_DEBUG,=20"Error=20while=20= queueing=20audio=20frame",=20ret);=0A=20=20=20=20=20}=0A=20=0A-=20=20=20=20= _context->current_audio_frame=20=3D=20= (CMSampleBufferRef)CFRetain(audioFrame);=0A-=0A-=20=20=20=20= unlock_frames(_context);=0A-=0A-=20=20=20=20= ++_context->audio_frames_captured;=0A+=20=20=20=20CFRetain(audioFrame);=0A= =20}=0A=20=0A=20@end=0A@@=20-287,6=20+274,19=20@@=20static=20void=20= destroy_context(AVFContext*=20ctx)=0A=20=20=20=20=20[ctx->avf_delegate=20= =20=20=20release];=0A=20=20=20=20=20[ctx->avf_audio_delegate=20release];=0A= =20=0A+=20=20=20=20CMSampleBufferRef=20frame;=0A+=0A+=20=20=20=20if=20= (ctx->frames_queue)=20{=0A+=20=20=20=20=20=20=20=20frame=20=3D=20= (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->frames_queue);=0A+=20=20=20=20= =20=20=20=20while=20(frame)=20{=0A+=20=20=20=20=20=20=20=20=20=20= CFRelease(frame);=0A+=20=20=20=20=20=20=20=20=20=20frame=20=3D=20= (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->frames_queue);=0A+=20=20=20=20= =20=20=20=20}=0A+=0A+=20=20=20=20=20=20=20=20= CFRelease(ctx->frames_queue);=0A+=20=20=20=20=20=20=20=20= ctx->frames_queue=20=3D=20NULL;=0A+=20=20=20=20}=0A+=0A=20=20=20=20=20= ctx->capture_session=20=3D=20NULL;=0A=20=20=20=20=20ctx->video_output=20=20= =20=20=3D=20NULL;=0A=20=20=20=20=20ctx->audio_output=20=20=20=20=3D=20= NULL;=0A@@=20-327,15=20+327,14=20@@=20static=20int=20= configure_video_device(AVFormatContext=20*s,=20AVCaptureDevice=20= *video_dev=0A=20=20=20=20=20NSObject=20*format=20=3D=20nil;=0A=20=20=20=20= =20NSObject=20*selected_range=20=3D=20nil;=0A=20=20=20=20=20NSObject=20= *selected_format=20=3D=20nil;=0A+=20=20=20=20CMFormatDescriptionRef=20= formatDescription;=0A+=20=20=20=20CMVideoDimensions=20dimensions;=0A=20=0A= =20=20=20=20=20//=20try=20to=20configure=20format=20by=20formats=20list=0A= =20=20=20=20=20//=20might=20raise=20an=20exception=20if=20no=20format=20= list=20is=20given=0A=20=20=20=20=20//=20(then=20fallback=20to=20default,=20= no=20configuration)=0A=20=20=20=20=20@try=20{=0A=20=20=20=20=20=20=20=20=20= for=20(format=20in=20[video_device=20valueForKey:@"formats"])=20{=0A-=20=20= =20=20=20=20=20=20=20=20=20=20CMFormatDescriptionRef=20= formatDescription;=0A-=20=20=20=20=20=20=20=20=20=20=20=20= CMVideoDimensions=20dimensions;=0A-=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20formatDescription=20=3D=20(CMFormatDescriptionRef)=20[format=20= performSelector:@selector(formatDescription)];=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20dimensions=20=3D=20= CMVideoFormatDescriptionGetDimensions(formatDescription);=0A=20=0A@@=20= -362,6=20+361,9=20@@=20static=20int=20= configure_video_device(AVFormatContext=20*s,=20AVCaptureDevice=20= *video_dev=0A=20=20=20=20=20=20=20=20=20=20=20=20=20goto=20= unsupported_format;=0A=20=20=20=20=20=20=20=20=20}=0A=20=0A+=20=20=20=20=20= =20=20=20ctx->width=20=20=3D=20dimensions.width;=0A+=20=20=20=20=20=20=20= =20ctx->height=20=3D=20dimensions.height;=0A+=0A=20=20=20=20=20=20=20=20=20= if=20(!selected_range)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= av_log(s,=20AV_LOG_ERROR,=20"Selected=20framerate=20(%f)=20is=20not=20= supported=20by=20the=20device.\n",=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20framerate);=0A@@=20-609,47=20+611,21=20@@=20static=20int=20= add_audio_device(AVFormatContext=20*s,=20AVCaptureDevice=20= *audio_device)=0A=20static=20int=20get_video_config(AVFormatContext=20= *s)=0A=20{=0A=20=20=20=20=20AVFContext=20*ctx=20=3D=20= (AVFContext*)s->priv_data;=0A-=20=20=20=20CVImageBufferRef=20= image_buffer;=0A-=20=20=20=20CMBlockBufferRef=20block_buffer;=0A-=20=20=20= =20CGSize=20image_buffer_size;=0A=20=20=20=20=20AVStream*=20stream=20=3D=20= avformat_new_stream(s,=20NULL);=0A=20=0A=20=20=20=20=20if=20(!stream)=20= {=0A=20=20=20=20=20=20=20=20=20return=201;=0A=20=20=20=20=20}=0A=20=0A-=20= =20=20=20//=20Take=20stream=20info=20from=20the=20first=20frame.=0A-=20=20= =20=20while=20(ctx->frames_captured=20<=201)=20{=0A-=20=20=20=20=20=20=20= =20CFRunLoopRunInMode(kCFRunLoopDefaultMode,=200.1,=20YES);=0A-=20=20=20=20= }=0A-=0A-=20=20=20=20lock_frames(ctx);=0A-=0A=20=20=20=20=20= ctx->video_stream_index=20=3D=20stream->index;=0A=20=0A=20=20=20=20=20= avpriv_set_pts_info(stream,=2064,=201,=20avf_time_base);=0A=20=0A-=20=20=20= =20image_buffer=20=3D=20= CMSampleBufferGetImageBuffer(ctx->current_frame);=0A-=20=20=20=20= block_buffer=20=3D=20CMSampleBufferGetDataBuffer(ctx->current_frame);=0A= -=0A-=20=20=20=20if=20(image_buffer)=20{=0A-=20=20=20=20=20=20=20=20= image_buffer_size=20=3D=20CVImageBufferGetEncodedSize(image_buffer);=0A-=0A= -=20=20=20=20=20=20=20=20stream->codecpar->codec_id=20=20=20=3D=20= AV_CODEC_ID_RAWVIDEO;=0A-=20=20=20=20=20=20=20=20= stream->codecpar->codec_type=20=3D=20AVMEDIA_TYPE_VIDEO;=0A-=20=20=20=20=20= =20=20=20stream->codecpar->width=20=20=20=20=20=20=3D=20= (int)image_buffer_size.width;=0A-=20=20=20=20=20=20=20=20= stream->codecpar->height=20=20=20=20=20=3D=20= (int)image_buffer_size.height;=0A-=20=20=20=20=20=20=20=20= stream->codecpar->format=20=20=20=20=20=3D=20ctx->pixel_format;=0A-=20=20= =20=20}=20else=20{=0A-=20=20=20=20=20=20=20=20stream->codecpar->codec_id=20= =20=20=3D=20AV_CODEC_ID_DVVIDEO;=0A-=20=20=20=20=20=20=20=20= stream->codecpar->codec_type=20=3D=20AVMEDIA_TYPE_VIDEO;=0A-=20=20=20=20=20= =20=20=20stream->codecpar->format=20=20=20=20=20=3D=20ctx->pixel_format;=0A= -=20=20=20=20}=0A-=0A-=20=20=20=20CFRelease(ctx->current_frame);=0A-=20=20= =20=20ctx->current_frame=20=3D=20nil;=0A-=0A-=20=20=20=20= unlock_frames(ctx);=0A+=20=20=20=20stream->codecpar->codec_id=20=20=20=3D=20= AV_CODEC_ID_RAWVIDEO;=0A+=20=20=20=20stream->codecpar->codec_type=20=3D=20= AVMEDIA_TYPE_VIDEO;=0A+=20=20=20=20stream->codecpar->width=20=20=20=20=20= =20=3D=20ctx->width;=0A+=20=20=20=20stream->codecpar->height=20=20=20=20=20= =3D=20ctx->height;=0A+=20=20=20=20stream->codecpar->format=20=20=20=20=20= =3D=20ctx->pixel_format;=0A=20=0A=20=20=20=20=20return=200;=0A=20}=0A@@=20= -682,7=20+658,6=20@@=20static=20int=20get_audio_config(AVFormatContext=20= *s)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20= =20=20default:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20av_log(ctx,=20= AV_LOG_ERROR,=20"Error:=20invalid=20sample=20format!\n");=0A-=20=20=20=20= =20=20=20=20=20=20=20=20unlock_frames(ctx);=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20return=20AVERROR(EINVAL);=0A=20=20=20=20=20}=0A=20=0A@@=20= -697,10=20+672,8=20@@=20static=20int=20get_audio_config(AVFormatContext=20= *s)=0A=20=20=20=20=20}];=0A=20=0A=20=20=20=20=20stream=20=3D=20= avformat_new_stream(s,=20NULL);=0A-=20=20=20=20if=20(!stream)=20{=0A-=20=20= =20=20=20=20=20=20unlock_frames(ctx);=0A+=20=20=20=20if=20(!stream)=0A=20= =20=20=20=20=20=20=20=20return=20-1;=0A-=20=20=20=20}=0A=20=0A=20=20=20=20= =20avpriv_set_pts_info(stream,=2064,=201,=20avf_time_base);=0A=20=0A@@=20= -712,7=20+685,6=20@@=20static=20int=20get_audio_config(AVFormatContext=20= *s)=0A=20=0A=20=20=20=20=20ctx->audio_stream_index=20=3D=20= stream->index;=0A=20=0A-=20=20=20=20unlock_frames(ctx);=0A=20=20=20=20=20= return=200;=0A=20}=0A=20=0A@@=20-729,8=20+701,6=20@@=20static=20int=20= avf_read_header(AVFormatContext=20*s)=0A=20=0A=20=20=20=20=20= ctx->num_video_devices=20=3D=20[devices=20count]=20+=20[devices_muxed=20= count];=0A=20=0A-=20=20=20=20pthread_mutex_init(&ctx->frame_lock,=20= NULL);=0A-=0A=20#if=20!TARGET_OS_IPHONE=20&&=20= __MAC_OS_X_VERSION_MIN_REQUIRED=20>=3D=201070=0A=20=20=20=20=20= CGGetActiveDisplayList(0,=20NULL,=20&num_screens);=0A=20#endif=0A@@=20= -931,6=20+901,14=20@@=20static=20int=20avf_read_header(AVFormatContext=20= *s)=0A=20=20=20=20=20//=20Initialize=20capture=20session=0A=20=20=20=20=20= ctx->capture_session=20=3D=20[[AVCaptureSession=20alloc]=20init];=0A=20=0A= +=20=20=20=20OSStatus=20ret;=0A+=20=20=20=20ret=20=3D=20= CMSimpleQueueCreate(kCFAllocatorDefault,=20ctx->max_frames,=20= &ctx->frames_queue);=0A+=0A+=20=20=20=20if=20(ret=20!=3D=20noErr)=20{=0A= +=20=20=20=20=20=20=20=20av_log_avfoundation(s,=20AV_LOG_ERROR,=20"error=20= while=20creating=20frame=20queue",=20ret);=0A+=20=20=20=20=20=20=20=20= goto=20fail;=0A+=20=20=20=20}=0A+=0A=20=20=20=20=20if=20(video_device=20= &&=20add_video_device(s,=20video_device))=20{=0A=20=20=20=20=20=20=20=20=20= goto=20fail;=0A=20=20=20=20=20}=0A@@=20-961,7=20+939,8=20@@=20static=20= int=20avf_read_header(AVFormatContext=20*s)=0A=20fail:=0A=20=20=20=20=20= [pool=20release];=0A=20=20=20=20=20destroy_context(ctx);=0A-=20=20=20=20= return=20AVERROR(EIO);=0A+=20=20=20=20av_log(s,=20AV_LOG_ERROR,=20"Error=20= while=20opening=20AVfoundation=20capture=20session\n");=0A+=20=20=20=20= return=20AVERROR_EXTERNAL;=0A=20}=0A=20=0A=20static=20int=20= copy_cvpixelbuffer(AVFormatContext=20*s,=0A@@=20-1010,39=20+989,46=20@@=20= static=20int=20copy_cvpixelbuffer(AVFormatContext=20*s,=0A=20static=20= int=20avf_read_packet(AVFormatContext=20*s,=20AVPacket=20*pkt)=0A=20{=0A=20= =20=20=20=20OSStatus=20ret;=0A+=20=20=20=20int=20status,=20length;=0A+=20= =20=20=20CMBlockBufferRef=20block_buffer;=0A+=20=20=20=20= CMSampleBufferRef=20frame;=0A+=20=20=20=20CMFormatDescriptionRef=20= format;=0A=20=20=20=20=20AVFContext*=20ctx=20=3D=20= (AVFContext*)s->priv_data;=0A+=20=20=20=20CMItemCount=20count;=0A+=20=20=20= =20CMSampleTimingInfo=20timing_info;=0A+=20=20=20=20CVImageBufferRef=20= image_buffer;=0A+=20=20=20=20size_t=20buffer_size;=0A+=20=20=20=20= AVRational=20timebase_q;=0A=20=0A-=20=20=20=20do=20{=0A-=20=20=20=20=20=20= =20=20CVImageBufferRef=20image_buffer;=0A-=20=20=20=20=20=20=20=20= CMBlockBufferRef=20block_buffer;=0A-=20=20=20=20=20=20=20=20= lock_frames(ctx);=0A+=20=20=20=20if=20= (CMSimpleQueueGetCount(ctx->frames_queue)=20<=201)=0A+=20=20=20=20=20=20=20= =20return=20AVERROR(EAGAIN);=0A=20=0A-=20=20=20=20=20=20=20=20if=20= (ctx->current_frame=20!=3D=20nil)=20{=0A-=20=20=20=20=20=20=20=20=20=20=20= =20int=20status;=0A-=20=20=20=20=20=20=20=20=20=20=20=20int=20length=20=3D= =200;=0A+=20=20=20=20frame=20=3D=20= (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->frames_queue);=0A+=20=20=20=20= format=20=3D=20CMSampleBufferGetFormatDescription(frame);=0A=20=0A-=20=20= =20=20=20=20=20=20=20=20=20=20image_buffer=20=3D=20= CMSampleBufferGetImageBuffer(ctx->current_frame);=0A-=20=20=20=20=20=20=20= =20=20=20=20=20block_buffer=20=3D=20= CMSampleBufferGetDataBuffer(ctx->current_frame);=0A+=20=20=20=20switch=20= (CMFormatDescriptionGetMediaType(format))=20{=0A+=20=20=20=20=20=20=20=20= case=20kCMMediaType_Video:=0A+=20=20=20=20=20=20=20=20=20=20=20=20length=20= =3D=200;=0A+=20=20=20=20=20=20=20=20=20=20=20=20image_buffer=20=3D=20= CMSampleBufferGetImageBuffer(frame);=0A+=20=20=20=20=20=20=20=20=20=20=20= =20block_buffer=20=3D=20CMSampleBufferGetDataBuffer(frame);=0A=20=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20if=20(image_buffer=20!=3D=20nil)=20{=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20length=20=3D=20= (int)CVPixelBufferGetDataSize(image_buffer);=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20}=20else=20if=20(block_buffer=20!=3D=20nil)=20{=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20length=20=3D=20= (int)CMBlockBufferGetDataLength(block_buffer);=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20}=20else=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20unlock_frames(ctx);=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20CFRelease(frame);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20return=20AVERROR(EINVAL);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =20=0A-=20=20=20=20=20=20=20=20=20=20=20=20if=20(av_new_packet(pkt,=20= length)=20<=200)=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= unlock_frames(ctx);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= return=20AVERROR(EIO);=0A+=20=20=20=20=20=20=20=20=20=20=20=20status=20=3D= =20av_new_packet(pkt,=20length);=0A+=20=20=20=20=20=20=20=20=20=20=20=20= if=20(status=20<=200)=20{=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20CFRelease(frame);=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= return=20status;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=0A-=20=20= =20=20=20=20=20=20=20=20=20=20CMItemCount=20count;=0A-=20=20=20=20=20=20=20= =20=20=20=20=20CMSampleTimingInfo=20timing_info;=0A-=0A-=20=20=20=20=20=20= =20=20=20=20=20=20if=20= (CMSampleBufferGetOutputSampleTimingInfoArray(ctx->current_frame,=201,=20= &timing_info,=20&count)=20=3D=3D=20noErr)=20{=0A-=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20AVRational=20timebase_q=20=3D=20av_make_q(1,=20= timing_info.presentationTimeStamp.timescale);=0A+=20=20=20=20=20=20=20=20= =20=20=20=20if=20(CMSampleBufferGetOutputSampleTimingInfoArray(frame,=20= 1,=20&timing_info,=20&count)=20=3D=3D=20noErr)=20{=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20timebase_q=20=3D=20av_make_q(1,=20= timing_info.presentationTimeStamp.timescale);=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20pkt->pts=20=3D=20pkt->dts=20=3D=20= av_rescale_q(timing_info.presentationTimeStamp.value,=20timebase_q,=20= avf_time_base_q);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=0A@@=20= -1055,62=20+1041,50=20@@=20static=20int=20= avf_read_packet(AVFormatContext=20*s,=20AVPacket=20*pkt)=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20status=20=3D=200;=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20ret=20=3D=20= CMBlockBufferCopyDataBytes(block_buffer,=200,=20pkt->size,=20pkt->data);=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(ret=20!=3D=20= kCMBlockBufferNoErr)=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20status=20=3D=20AVERROR(EIO);=0A+=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20av_log_avfoundation(s,=20AV_LOG_ERROR,=20= "error=20while=20copying=20buffer=20data",=20ret);=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20status=20=3D=20AVERROR_EXTERNAL;=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20= =20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=20=20=20=20=20=20= CFRelease(ctx->current_frame);=0A-=20=20=20=20=20=20=20=20=20=20=20=20= ctx->current_frame=20=3D=20nil;=0A-=0A-=20=20=20=20=20=20=20=20=20=20=20=20= if=20(status=20<=200)=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20unlock_frames(ctx);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= return=20status;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A-=20=20=20=20= =20=20=20=20}=20else=20if=20(ctx->current_audio_frame=20!=3D=20nil)=20{=0A= -=20=20=20=20=20=20=20=20=20=20=20=20CMBlockBufferRef=20block_buffer=20=3D= =20CMSampleBufferGetDataBuffer(ctx->current_audio_frame);=0A+=20=20=20=20= =20=20=20=20=20=20=20=20CFRelease(frame);=0A=20=0A-=20=20=20=20=20=20=20=20= =20=20=20=20size_t=20buffer_size=20=3D=20= CMBlockBufferGetDataLength(block_buffer);=0A+=20=20=20=20=20=20=20=20=20=20= =20=20return=20status;=0A=20=0A-=20=20=20=20=20=20=20=20=20=20=20=20int=20= status=20=3D=20av_new_packet(pkt,=20buffer_size);=0A+=20=20=20=20=20=20=20= =20case=20kCMMediaType_Audio:=0A+=20=20=20=20=20=20=20=20=20=20=20=20= block_buffer=20=3D=20CMSampleBufferGetDataBuffer(frame);=0A+=20=20=20=20=20= =20=20=20=20=20=20=20buffer_size=20=3D=20= CMBlockBufferGetDataLength(block_buffer);=0A+=0A+=20=20=20=20=20=20=20=20= =20=20=20=20status=20=3D=20av_new_packet(pkt,=20buffer_size);=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20if=20(status=20<=200)=20{=0A-=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20unlock_frames(ctx);=0A+=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20CFRelease(frame);=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20return=20status;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20}=0A=20=0A=20=20=20=20=20=20=20=20=20=20=20=20=20ret=20=3D=20= CMBlockBufferCopyDataBytes(block_buffer,=200,=20pkt->size,=20pkt->data);=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20if=20(ret=20!=3D=20= kCMBlockBufferNoErr)=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20unlock_frames(ctx);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= return=20AVERROR(EIO);=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= CFRelease(frame);=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= av_log_avfoundation(s,=20AV_LOG_ERROR,=20"error=20while=20copying=20= audio=20data",=20ret);=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= return=20AVERROR_EXTERNAL;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20= =0A-=20=20=20=20=20=20=20=20=20=20=20=20CMItemCount=20count;=0A-=20=20=20= =20=20=20=20=20=20=20=20=20CMSampleTimingInfo=20timing_info;=0A-=0A-=20=20= =20=20=20=20=20=20=20=20=20=20if=20= (CMSampleBufferGetOutputSampleTimingInfoArray(ctx->current_audio_frame,=20= 1,=20&timing_info,=20&count)=20=3D=3D=20noErr)=20{=0A-=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20AVRational=20timebase_q=20=3D=20av_make_q(1,=20= timing_info.presentationTimeStamp.timescale);=0A+=20=20=20=20=20=20=20=20= =20=20=20=20if=20(CMSampleBufferGetOutputSampleTimingInfoArray(frame,=20= 1,=20&timing_info,=20&count)=20=3D=3D=20noErr)=20{=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20timebase_q=20=3D=20av_make_q(1,=20= timing_info.presentationTimeStamp.timescale);=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20pkt->pts=20=3D=20pkt->dts=20=3D=20= av_rescale_q(timing_info.presentationTimeStamp.value,=20timebase_q,=20= avf_time_base_q);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20pkt->stream_index=20=20=3D=20= ctx->audio_stream_index;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= pkt->flags=20=20=20=20=20=20=20=20|=3D=20AV_PKT_FLAG_KEY;=0A=20=0A-=20=20= =20=20=20=20=20=20=20=20=20=20CFRelease(ctx->current_audio_frame);=0A-=20= =20=20=20=20=20=20=20=20=20=20=20ctx->current_audio_frame=20=3D=20nil;=0A= -=0A-=20=20=20=20=20=20=20=20=20=20=20=20unlock_frames(ctx);=0A-=20=20=20= =20=20=20=20=20}=20else=20{=0A+=20=20=20=20=20=20=20=20=20=20=20=20= CFRelease(frame);=0A+=20=20=20=20=20=20=20=20=20=20=20=20return=200;=0A+=20= =20=20=20=20=20=20=20default:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= pkt->data=20=3D=20NULL;=0A-=20=20=20=20=20=20=20=20=20=20=20=20= unlock_frames(ctx);=0A-=20=20=20=20=20=20=20=20=20=20=20=20if=20= (ctx->observed_quit)=20{=0A+=20=20=20=20=20=20=20=20=20=20=20=20if=20= (ctx->observed_quit)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= return=20AVERROR_EOF;=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=20else=20= {=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20= AVERROR(EAGAIN);=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A-=20=20=20=20= =20=20=20=20}=0A=20=0A-=20=20=20=20=20=20=20=20unlock_frames(ctx);=0A-=20= =20=20=20}=20while=20(!pkt->data);=0A+=20=20=20=20=20=20=20=20=20=20=20=20= return=20AVERROR(EAGAIN);=0A+=20=20=20=20}=0A=20=0A-=20=20=20=20return=20= 0;=0A+=20=20=20=20return=20AVERROR_BUG;=0A=20}=0A=20=0A=20static=20int=20= avf_close(AVFormatContext=20*s)=0A@@=20-1135,6=20+1109,7=20@@=20static=20= int=20avf_close(AVFormatContext=20*s)=0A=20=20=20=20=20{=20= "capture_mouse_clicks",=20"capture=20the=20screen=20mouse=20clicks",=20= offsetof(AVFContext,=20capture_mouse_clicks),=20AV_OPT_TYPE_BOOL,=20= {.i64=3D0},=200,=201,=20AV_OPT_FLAG_DECODING_PARAM=20},=0A=20=20=20=20=20= {=20"capture_raw_data",=20"capture=20the=20raw=20data=20from=20device=20= connection",=20offsetof(AVFContext,=20capture_raw_data),=20= AV_OPT_TYPE_BOOL,=20{.i64=3D0},=200,=201,=20AV_OPT_FLAG_DECODING_PARAM=20= },=0A=20=20=20=20=20{=20"drop_late_frames",=20"drop=20frames=20that=20= are=20available=20later=20than=20expected",=20offsetof(AVFContext,=20= drop_late_frames),=20AV_OPT_TYPE_BOOL,=20{.i64=3D1},=200,=201,=20= AV_OPT_FLAG_DECODING_PARAM=20},=0A+=20=20=20=20{=20"max_frames",=20= "Maximun=20length=20of=20the=20queue=20of=20pending=20frames",=20= offsetof(AVFContext,=20max_frames),=20AV_OPT_TYPE_INT,=20{.i64=3D10},=20= 0,=20INT_MAX,=20AV_OPT_FLAG_DECODING_PARAM=20},=0A=20=0A=20=20=20=20=20{=20= NULL=20},=0A=20};=0A--=20=0A2.32.0=20(Apple=20Git-132)=0A=0A= --Apple-Mail=_D30E3475-BFBB-437F-9BA6-6B47CF86A6B9 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". --Apple-Mail=_D30E3475-BFBB-437F-9BA6-6B47CF86A6B9--