[vlc-devel] [PATCH 1/3] qtsound: added audio capture functionality for MAC OS X

Rémi Denis-Courmont remi at remlab.net
Wed Oct 5 15:11:41 CEST 2011


On Wed,  5 Oct 2011 14:10:07 +0200, Michael Feurstein
<michael.feurstein at gmail.com> wrote:
> Tested with Built-in Input, Built-in Microphone and Griffin iMic USB
system
> Usage: qtsound://"Built-In Input" or qtsound://"iMic USB audio system"
> ---
>  configure.ac              |   30 ++-
>  modules/access/Modules.am |    1 +
>  modules/access/qtsound.m  |  562
>  +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 587 insertions(+), 6 deletions(-)
>  create mode 100644 modules/access/qtsound.m
> 
> diff --git a/configure.ac b/configure.ac
> index 02d7c72..a4e43be 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -2124,11 +2124,11 @@ then
>  fi
>  
>  dnl
> -dnl QTCapture
> -AC_ARG_ENABLE(macosx-qtcapture,
> -  [  --enable-macosx-qtcapture Mac OS X qtcapture (iSight) module
> (default enabled on Mac OS X)])
> -if test "x${enable_macosx_qtcapture}" != "xno" &&
> -  (test "${SYS}" = "darwin" || test "${enable_macosx_qtcapture}" =
"yes")
> +dnl QTKit
> +AC_ARG_ENABLE(macosx-qtkit,
> +  [  --enable-macosx-qtkit Mac OS X qtkit framework for video and audio
> (default enabled on Mac OS X)])
> +if test "x${enable_macosx_qtkit}" != "xno" &&
> +  (test "${SYS}" = "darwin" || test "${enable_macosx_qtkit}" = "yes")
>  then
>    VLC_ADD_LIBS([qtcapture], [-Wl,-framework,Cocoa])
>    VLC_ADD_LIBS([qtcapture], [-Wl,-framework,QTKit])
> @@ -2136,9 +2136,12 @@ then
>    VLC_ADD_LIBS([qtcapture], [-Wl,-framework,QuartzCore])
>    VLC_ADD_LIBS([qtcapture], [-Wl,-framework,CoreVideo])
>    VLC_ADD_PLUGIN([qtcapture])
> +  VLC_ADD_LIBS([qtsound], [-Wl,-framework,Cocoa])
> +  VLC_ADD_LIBS([qtsound], [-Wl,-framework,QTKit])
> +  VLC_ADD_LIBS([qtsound], [-Wl,-framework,CoreAudio])
> +  VLC_ADD_PLUGIN([qtsound])
>  fi

There is not much point in cluttering configure with constant values. You
might as well pass them as _LIBADD or _LDFLAGS in the Makefile
(Modules.am).

>  
> -
>  dnl
>  dnl  Demux plugins
>  dnl
> @@ -3766,6 +3769,21 @@ then
>    VLC_ADD_PLUGIN([macosx_dialog_provider])
>  fi
>  
> +
> +AC_ARG_ENABLE(macosx-eyetv,
> +  [  --enable-macosx-eyetv   Mac OS X EyeTV (TNT Tuner) module (default
> enabled on Mac OS X)])
> +if test "x${enable_macosx_eyetv}" != "xno" &&
> +  (test "${SYS}" = "darwin" || test "${enable_macosx_eyetv}" = "yes")
> +then
> +  VLC_ADD_LIBS([access_eyetv], [-Wl,-framework,Foundation])
> +  VLC_ADD_PLUGIN([access_eyetv])
> +fi
> +
> +AC_ARG_ENABLE(macosx-vlc-app,
> +  [  --enable-macosx-vlc-app build the VLC media player (default
enabled
> on Mac OS X)])
> +AM_CONDITIONAL(BUILD_MACOSX_VLC_APP, [test "${enable_macosx_vlc_app}"
!=
> "no" &&
> +    (test "${SYS}" = "darwin" || test "${enable_macosx_vlc_app}" =
"yes")
> ])
> +

This does not belong in this patch or I missed something.

>  dnl
>  dnl  ncurses module
>  dnl
> diff --git a/modules/access/Modules.am b/modules/access/Modules.am
> index 8b4d22d..b81b2dc 100644
> --- a/modules/access/Modules.am
> +++ b/modules/access/Modules.am
> @@ -56,6 +56,7 @@ SOURCES_dvdread = dvdread.c
>  SOURCES_dc1394 = dc1394.c
>  SOURCES_pvr = pvr.c
>  SOURCES_qtcapture = qtcapture.m
> +SOURCES_qtsound = qtsound.m
>  SOURCES_linsys_sdi = linsys/linsys_sdi.c linsys/linsys_sdi.h
>  SOURCES_linsys_hdsdi = \
>  	linsys/linsys_hdsdi.c \
> diff --git a/modules/access/qtsound.m b/modules/access/qtsound.m
> new file mode 100644
> index 0000000..d29c21c
> --- /dev/null
> +++ b/modules/access/qtsound.m
> @@ -0,0 +1,562 @@
>
+/*****************************************************************************
> +* qtsound.m: qtkit (Mac OS X) based audio capture module
>
+*****************************************************************************
> +* Copyright (C) 2011 the VideoLAN team
> +*
> +* Authors: Pierre d'Herbemont <pdherbemont at videolan.org>
> +*          Gustaf Neumann <neumann at wu.ac.at>
> +*          Michael Feurstein <michael.feurstein at wu.ac.at>
> +*
>
+*****************************************************************************
> +* This library is free software; you can redistribute it and/or
> +* modify it under the terms of the GNU Lesser General Public License
> +* as published by the Free Software Foundation; either version 2.1
> +* of the License, or (at your option) any later version.
> +*
> +* This library is distributed in the hope that it will be useful,
> +* but WITHOUT ANY WARRANTY; without even the implied warranty of
> +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> +* Lesser General Public License for more details.
> +*
> +* You should have received a copy of the GNU Lesser General Public
> +* License along with this library; if not, write to the Free Software
> +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
> +*
>
+*****************************************************************************/
> +
>
+/*****************************************************************************
> + * Preamble
> +
>
*****************************************************************************/
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <vlc_common.h>
> +#include <vlc_plugin.h>
> +#include <vlc_aout.h>
> +
> +#include <vlc_demux.h>
> +#include <vlc_dialog.h>
> +
> +#import <QTKit/QTKit.h>
> +
>
+/*****************************************************************************
> + * Local prototypes.
> +
>
*****************************************************************************/
> +static int Open( vlc_object_t *p_this );
> +static void Close( vlc_object_t *p_this );
> +static int Demux( demux_t *p_demux );
> +static int Control( demux_t *, int, va_list );
> +
>
+/*****************************************************************************
> + * Module descriptor
> +
>
*****************************************************************************/
> +
> +vlc_module_begin()
> +set_shortname( N_("QTSound") )
> +set_description( N_("Quicktime Sound Capture") )
> +set_category( CAT_INPUT )
> +set_subcategory( SUBCAT_INPUT_ACCESS )
> +add_shortcut( "qtsound" )
> +set_capability( "access_demux", 0 )
> +set_callbacks( Open, Close )
> +vlc_module_end ()
> +
> +
>
+/*****************************************************************************
> + * QTKit Bridge
> +
>
*****************************************************************************/
> + at interface VLCDecompressedAudioOutput :
QTCaptureDecompressedAudioOutput
> +{
> +    AudioBuffer *currentAudioBuffer;
> +    int lenghtForAllSamples, numberOfSamples;
> +    date_t date;
> +    mtime_t currentPts;
> +    mtime_t previousPts;
> +}
> +- (id)init;
> +- (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer
> fromConnection:(QTCaptureConnection *)connection;
> +- (mtime_t)copyCurrentAudioBytesToBuffer:(void *)buffer;
> + at end
> +
> + at implementation VLCDecompressedAudioOutput :
> QTCaptureDecompressedAudioOutput
> +- (id)init
> +{
> +    if( self = [super init] )
> +    {
> +        currentAudioBuffer = nil;
> +        date_Init(&date, 44100, 1);
> +        date_Set(&date,0);
> +        currentPts = 0;
> +        previousPts = 0;
> +    }
> +    return self;
> +}
> +- (void)dealloc
> +{
> +    @synchronized (self)
> +    {
> +        free(currentAudioBuffer);
> +        currentAudioBuffer = nil;
> +    }
> +    [super dealloc];
> +}
> +
> +- (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer
> fromConnection:(QTCaptureConnection *)connection
> +{
> +    AudioBufferList *tempAudioBufferList;
> +    NSMutableData *rawAudioData;
> +    int audioDataSize = 0;
> +    UInt32 count = 0;
> +
> +    @synchronized (self)
> +    {
> +        date_Increment(&date,512);

Where is 512 coming from?

> +        currentPts = date_Get(&date);
> +
> +        QTFormatDescription *audio_format = [sampleBuffer
> formatDescription];
> +
> +        tempAudioBufferList = [sampleBuffer
audioBufferListWithOptions:0];
> +        if (tempAudioBufferList->mNumberBuffers > 1)
> +        {
> +            for ( count = 0; count <
tempAudioBufferList->mNumberBuffers;
> count++ )
> +            {
> +                audioDataSize +=
> tempAudioBufferList->mBuffers[count].mDataByteSize;
> +            }
> +            rawAudioData = malloc(audioDataSize * 2);
> +            if (NULL == rawAudioData)
> +            {
> +                free(rawAudioData);
> +                return;
> +            }
> +        }
> +
> +        /* Interleave raw data
> +         * The provided data by QTKit is not interleaved according to
> information from ASBD
> +         * See Format Comment in Open for detailed info on what QTKit
> provides us with
> +         */
> +        if ( audioDataSize )
> +        {
> +            unsigned short i;
> +            const float *b1Ptr, *b2Ptr;
> +            float *uPtr;
> +
> +            for (i = 0,
> +                 uPtr = (float *)rawAudioData,
> +                 b1Ptr = (const float *)
> tempAudioBufferList->mBuffers[0].mData,
> +                 b2Ptr = (const float *)
> tempAudioBufferList->mBuffers[1].mData;
> +                 i < 512; i++)
> +            {
> +                *uPtr = *b1Ptr;
> +                uPtr ++;
> +                b1Ptr ++;
> +                *uPtr = *b2Ptr;
> +                uPtr ++;
> +                b2Ptr ++;
> +            }
> +
> +            if (currentAudioBuffer == nil)
> +            {
> +                currentAudioBuffer = (AudioBuffer
> *)malloc(sizeof(AudioBuffer));
> +                if (NULL == currentAudioBuffer)
> +                {
> +                    free(rawAudioData);
> +                    return;
> +                }
> +            }
> +            currentAudioBuffer->mNumberChannels = 2;
> +            currentAudioBuffer->mDataByteSize = audioDataSize;
> +            currentAudioBuffer->mData = rawAudioData;
> +        }
> +    }
> +}
> +
> +- (mtime_t)copyCurrentAudioBytesToBuffer:(void *)buffer
> +{
> +    AudioBuffer *audioBuffer;
> +    mtime_t pts;
> +
> +    if( !currentAudioBuffer || currentPts == previousPts )
> +    {
> +        return 0;
> +    }
> +
> +    @synchronized (self)
> +    {
> +        pts = previousPts = currentPts;
> +        /* copy raw data */
> +        memcpy( buffer, currentAudioBuffer->mData,
> currentAudioBuffer->mDataByteSize );
> +    }
> +
> +    return (currentAudioBuffer->mData) ? currentPts : 0;
> +}
> +
> + at end
> +
>
+/*****************************************************************************
> + * Struct
> +
>
*****************************************************************************/
> +
> +struct demux_sys_t {
> +    QTCaptureSession * session;
> +    QTCaptureDevice * audiodevice;
> +    VLCDecompressedAudioOutput * audiooutput;
> +    block_t *p_block_audio;

p_block_audio does not seem to be used anywhere

> +    es_out_id_t *p_es_audio;
> +    int i_audio_max_buffer_size;
> +};
> +
>
+/*****************************************************************************
> + * Open: initialize interface
> +
>
*****************************************************************************/
> +static int Open( vlc_object_t *p_this )
> +{
> +    demux_t *p_demux = (demux_t*)p_this;
> +    demux_sys_t *p_sys;
> +    es_format_t audiofmt;
> +    int result = 0;
> +    char *psz_uid = NULL;
> +
> +    /* Only when selected */
> +    if( *p_demux->psz_access == '\0' )
> +        return VLC_EGENERIC;
> +
> +    if( p_demux->psz_location && *p_demux->psz_location )
> +    {
> +        psz_uid = p_demux->psz_location;
> +    }
> +    msg_Dbg( p_demux, "qtsound uid = %s", psz_uid );
> +    NSString *qtk_curraudiodevice_uid = [[NSString alloc]
> initWithFormat:@"%s", psz_uid];
> +
> +    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
> +
> +    p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
> +    if( !p_sys )
> +        return VLC_ENOMEM;
> +
> +    msg_Dbg( p_demux, "qtsound : uid = %s", [qtk_curraudiodevice_uid
> UTF8String]);
> +    NSArray *myAudioDevices = [[[QTCaptureDevice
> inputDevicesWithMediaType:QTMediaTypeSound]
> arrayByAddingObjectsFromArray:[QTCaptureDevice
> inputDevicesWithMediaType:QTMediaTypeMuxed]] retain];
> +    if([myAudioDevices count] == 0)
> +    {
> +        dialog_FatalWait( p_demux, _("No Audio Input device found"),
> +                         _("Your Mac does not seem to be equipped with
a
> suitable audio input device."
> +                     "Please check your connectors and drivers.") );
> +        msg_Err( p_demux, "Can't find any Audio device" );
> +
> +        goto error;
> +    }
> +    int iaudio;
> +    for(iaudio = 0; iaudio < [myAudioDevices count]; iaudio++){
> +        QTCaptureDevice *qtk_audioDevice;
> +        qtk_audioDevice = [myAudioDevices objectAtIndex:iaudio];
> +        msg_Dbg( p_demux, "qtsound audio %d/%d localizedDisplayName: %s
> uniqueID: %s", iaudio, [myAudioDevices count], [[qtk_audioDevice
> localizedDisplayName] UTF8String], [[qtk_audioDevice uniqueID]
> UTF8String]);
> +        if([[[qtk_audioDevice
> localizedDisplayName]stringByTrimmingCharactersInSet:[NSCharacterSet
> whitespaceCharacterSet]] isEqualToString:qtk_curraudiodevice_uid]){
> +            msg_Dbg( p_demux, "Device found" );
> +            break;
> +        }
> +    }
> +
> +    QTCaptureDeviceInput * audioInput = nil;
> +    NSError *o_returnedAudioError;
> +    if(iaudio < [myAudioDevices count]){
> +        p_sys->audiodevice = [myAudioDevices objectAtIndex:iaudio];
> +    }
> +    else
> +    {
> +        /* cannot find designated audio device, fall back to open
default
> audio device */
> +        msg_Dbg(p_demux, "Cannot find designated uid audio device as
%s.
> Fall back to open default audio device.", [qtk_curraudiodevice_uid
> UTF8String]);
> +        p_sys->audiodevice = [QTCaptureDevice
> defaultInputDeviceWithMediaType: QTMediaTypeSound];
> +    }
> +    if( !p_sys->audiodevice )
> +    {
> +        dialog_FatalWait( p_demux, _("No audio input device found"),
> +                         _("Your Mac does not seem to be equipped with
a
> suitable audio input device."
> +                     "Please check your connectors and drivers.") );
> +        msg_Err( p_demux, "Can't find any Audio device" );
> +
> +        goto error;
> +    }
> +
> +    if( ![p_sys->audiodevice open: &o_returnedAudioError] )
> +    {
> +        msg_Err( p_demux, "Unable to open the audio capture device
(%d)",
> [o_returnedAudioError code] );
> +        goto error;
> +    }
> +
> +    if( [p_sys->audiodevice isInUseByAnotherApplication] == YES )
> +    {
> +        msg_Err( p_demux, "default audio capture device is exclusively
in
> use by another application" );
> +        goto error;
> +    }
> +    audioInput = [[QTCaptureDeviceInput alloc] initWithDevice:
> p_sys->audiodevice];
> +    if( !audioInput )
> +    {
> +        msg_Err( p_demux, "can't create a valid audio capture input
> facility" );
> +        goto error;
> +    } else {
> +        msg_Dbg( p_demux, "created valid audio capture input facility"
);
> +    }
> +
> +    p_sys->audiooutput = [[VLCDecompressedAudioOutput alloc] init];
> +    msg_Dbg ( p_demux, "initialized audio output" );
> +
> +    /* Get the formats */
> +    /*
> +     FIXME: the format description gathered here does not seem to be
the
> same
> +     in comparison to the format description collected from the actual
> sampleBuffer.
> +     This information needs to be updated some other place. For the
time
> being this shall suffice.
> +
> +     The following verbose output is an example of what is read from
the
> input device during the below block
> +     [0x3042138] qtsound demux debug: Audio localized format summary:
> Linear PCM, 24 bit little-endian signed integer, 2 channels, 44100 Hz
> +     [0x3042138] qtsound demux debug: Sample Rate: 44100; Format ID:
> lpcm; Format Flags: 00000004; Bytes per Packet: 8; Frames per Packet: 1;
> Bytes per Frame: 8; Channels per Frame: 2; Bits per Channel: 24
> +     [0x3042138] qtsound demux debug: Flag float 0 bigEndian 0
signedInt
> 1 packed 0 alignedHigh 0 non interleaved 0 non mixable 0
> +     canonical 0 nativeFloatPacked 0 nativeEndian 0
> +
> +     However when reading this information from the sampleBuffer during
> the delegate call from
> +     - (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer
> fromConnection:(QTCaptureConnection *)connection;
> +     the following data shows up
> +     2011-09-23 22:06:03.077 VLC[23070:f103] Audio localized format
> summary: Linear PCM, 32 bit little-endian floating point, 2 channels,
44100
> Hz
> +     2011-09-23 22:06:03.078 VLC[23070:f103] Sample Rate: 44100; Format
> ID: lpcm; Format Flags: 00000029; Bytes per Packet: 4; Frames per
Packet:
> 1; Bytes per Frame: 4; Channels per Frame: 2; Bits per Channel: 32
> +     2011-09-23 22:06:03.078 VLC[23070:f103] Flag float 1 bigEndian 0
> signedInt 0 packed 1 alignedHigh 0 non interleaved 1 non mixable 0
> +     canonical 1 nativeFloatPacked 1 nativeEndian 0
> +
> +     Note the differences
> +     24bit vs. 32bit
> +     little-endian signed integer vs. little-endian floating point
> +     format flag 00000004 vs. 00000029
> +     bytes per packet 8 vs. 4
> +     packed 0 vs. 1
> +     non interleaved 0 vs. 1 -> this makes a major difference when
> filling our own buffer
> +     canonical 0 vs. 1
> +     nativeFloatPacked 0 vs. 1
> +
> +     One would assume we'd need to feed the (es_format_t)audiofmt with
> the data collected here.
> +     This is not the case. Audio will be transmitted in artefacts, due
to
> wrong information.
> +
> +     At the moment this data is set manually, however one should
consider
> trying to set this data dynamically
> +     */
> +    NSArray *audioformat_array = [p_sys->audiodevice
formatDescriptions];
> +    QTFormatDescription* audio_format = NULL;
> +    for( int k = 0; k < [audioformat_array count]; k++ )
> +    {
> +        audio_format = (QTFormatDescription *)[audioformat_array
> objectAtIndex: k];
> +
> +        msg_Dbg( p_demux, "Audio localized format summary: %s",
> [[audio_format localizedFormatSummary] UTF8String]);
> +        msg_Dbg( p_demux, "Audio format description attributes:
> %s",[[[audio_format formatDescriptionAttributes] description]
UTF8String]);
> +
> +        AudioStreamBasicDescription asbd = {0};
> +        NSValue *asbdValue =  [audio_format
>
attributeForKey:QTFormatDescriptionAudioStreamBasicDescriptionAttribute];
> +        [asbdValue getValue:&asbd];
> +
> +        char formatIDString[5];
> +        UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID);
> +        bcopy (&formatID, formatIDString, 4);
> +        formatIDString[4] = '\0';
> +
> +        /* kept for development purposes */
> +#if 0
> +        msg_Dbg( p_demux, "Sample Rate: %.0lf; Format ID: %s; Format
> Flags: %.8x; Bytes per Packet: %d; Frames per Packet: %d; Bytes per
Frame:
> %d; Channels per Frame: %d; Bits per Channel: %d",
> +                asbd.mSampleRate,
> +                formatIDString,
> +                asbd.mFormatFlags,
> +                asbd.mBytesPerPacket,
> +                asbd.mFramesPerPacket,
> +                asbd.mBytesPerFrame,
> +                asbd.mChannelsPerFrame,
> +                asbd.mBitsPerChannel);
> +
> +        msg_Dbg( p_demux, "Flag float %d bigEndian %d signedInt %d
packed
> %d alignedHigh %d non interleaved %d non mixable %d\ncanonical %d
> nativeFloatPacked %d nativeEndian %d",
> +                (asbd.mFormatFlags & kAudioFormatFlagIsFloat) != 0,
> +                (asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0,
> +                (asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger)
!=
> 0,
> +                (asbd.mFormatFlags & kAudioFormatFlagIsPacked) != 0,
> +                (asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) !=
0,
> +                (asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved)
!=
> 0,
> +                (asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) !=
0,
> +
> +                (asbd.mFormatFlags & kAudioFormatFlagsCanonical) != 0,
> +                (asbd.mFormatFlags &
kAudioFormatFlagsNativeFloatPacked)
> != 0,
> +                (asbd.mFormatFlags & kAudioFormatFlagsNativeEndian) !=
0
> +                );
> +#endif
> +    }
> +
> +    if( [audioformat_array count] )
> +        audio_format = [audioformat_array objectAtIndex: 0];
> +    else goto error;
> +
> +    /* Now we can init */
> +    int audiocodec = VLC_CODEC_FL32;
> +    es_format_Init( &audiofmt, AUDIO_ES, audiocodec);
> +
> +    audiofmt.audio.i_format = audiocodec;
> +    audiofmt.audio.i_rate = 44100;
> +    /* i_physical_channels Describes the channels configuration of the
> samples (ie. number of
> +     * channels which are available in the buffer, and positions). */
> +    audiofmt.audio.i_physical_channels = AOUT_CHAN_RIGHT |
AOUT_CHAN_LEFT;
> +    /* i_original_channels Describes from which original channels,
before
> downmixing, the
> +     * buffer is derived. */
> +    audiofmt.audio.i_original_channels = AOUT_CHAN_RIGHT |
AOUT_CHAN_LEFT;
> +    /* i_bytes_per_frame Optional - for A/52, SPDIF and DTS types : */
> +    /* Bytes used by one compressed frame, depends on bitrate. */
> +    audiofmt.audio.i_bytes_per_frame = 4;
> +    /* Number of sampleframes contained in one compressed frame. */
> +    audiofmt.audio.i_frame_length = 1;
> +    /* Please note that it may be completely arbitrary - buffers are
not
> +     * obliged to contain a integral number of so-called "frames". It's
> +     * just here for the division :
> +     * buffer_size = i_nb_samples * i_bytes_per_frame / i_frame_length
> +     */
> +    audiofmt.audio.i_bitspersample = 32;
> +    audiofmt.audio.i_channels = 2;
> +    audiofmt.audio.i_blockalign = audiofmt.audio.i_channels *
> audiofmt.audio.i_bitspersample / 16;
> +    audiofmt.i_bitrate = audiofmt.audio.i_channels *
> audiofmt.audio.i_rate * audiofmt.audio.i_bitspersample;
> +    p_sys->i_audio_max_buffer_size = 4096;
> +
> +    p_sys->session = [[QTCaptureSession alloc] init];
> +
> +    bool retAudio = [p_sys->session addInput:audioInput error:
> &o_returnedAudioError];
> +    if( !retAudio )
> +    {
> +        msg_Err( p_demux, "the audio capture device could not be added
to
> capture session (%d)", [o_returnedAudioError code] );
> +        goto error;
> +    }
> +
> +    bool retAudioOutput = [p_sys->session addOutput:p_sys->audiooutput
> error: &o_returnedAudioError];
> +    if( !retAudioOutput )
> +    {
> +        msg_Err( p_demux, "audio output could not be added to capture
> session (%d)", [o_returnedAudioError code] );
> +        goto error;
> +    }
> +
> +    [p_sys->session startRunning];
> +
> +    /* Set up p_demux */
> +    p_demux->pf_demux = Demux;
> +    p_demux->pf_control = Control;
> +    p_demux->info.i_update = 0;
> +    p_demux->info.i_title = 0;
> +    p_demux->info.i_seekpoint = 0;
> +
> +    msg_Dbg( p_demux, "New audio es %d channels %dHz",
> +            audiofmt.audio.i_channels, audiofmt.audio.i_rate );
> +
> +    p_sys->p_es_audio = es_out_Add( p_demux->out, &audiofmt );
> +
> +    [audioInput release];
> +    [pool release];
> +
> +    msg_Dbg( p_demux, "QTSound: We have an audio device ready!" );
> +
> +    return VLC_SUCCESS;
> +error:
> +    [audioInput release];
> +    [pool release];
> +
> +    free( p_sys );
> +
> +    return VLC_EGENERIC;
> +}
> +
>
+/*****************************************************************************
> + * Close: destroy interface
> +
>
*****************************************************************************/
> +static void Close( vlc_object_t *p_this )
> +{
> +    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
> +
> +    demux_t *p_demux = (demux_t*)p_this;
> +    demux_sys_t *p_sys = p_demux->p_sys;
> +
> +    /* Hack: if libvlc was killed, main interface thread was,
> +     * and poor QTKit needs it, so don't tell him.
> +     * Else we dead lock. */
> +    if( vlc_object_alive(p_this->p_libvlc))

No matter why you feel like you need to check the legacy b_die bit, it
certainly does not do whatever you wish it did.

> +    {
> +        // Perform this on main thread, as the framework itself will
> sometimes try to synchronously
> +        // work on main thread. And this will create a dead lock.
> +        [p_sys->session
> performSelectorOnMainThread:@selector(stopRunning) withObject:nil
> waitUntilDone:NO];
> +        [p_sys->audiooutput
> performSelectorOnMainThread:@selector(release) withObject:nil
> waitUntilDone:NO];
> +        [p_sys->session performSelectorOnMainThread:@selector(release)
> withObject:nil waitUntilDone:NO];
> +    }
> +    free( p_sys );
> +
> +    [pool release];
> +}
> +
>
+/*****************************************************************************
> + * Demux:
> +
>
*****************************************************************************/
> +static int Demux( demux_t *p_demux )
> +{
> +    demux_sys_t *p_sys = p_demux->p_sys;
> +    block_t *p_blocka;
> +
> +    p_blocka = block_New( p_demux, p_sys->i_audio_max_buffer_size );
> +
> +    if( !p_blocka )
> +    {
> +        msg_Err( p_demux, "cannot get audio block" );
> +        return 0;
> +    }
> +
> +    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
> +
> +    @synchronized (p_sys->audiooutput)
> +    {
> +        p_blocka->i_pts = [p_sys->audiooutput
> copyCurrentAudioBytesToBuffer: p_blocka->p_buffer];

It seems to me that you are copying the data twice.

There should be no need to copy blocks data at all since deinterleaving
does it on the fly.

> +        /* FIXME: set this dynamically */
> +        p_blocka->i_nb_samples = 512;
> +        p_blocka->i_buffer = 4096;
> +    }
> +
> +    if( !p_blocka->i_pts )
> +    {
> +        // Nothing to transfer yet, just forget
> +        block_Release( p_blocka );
> +        [pool release];
> +        msleep( 10000 );
> +        return 1;
> +    }
> +
> +    [pool release];
> +
> +    if( p_blocka )
> +    {
> +        es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_blocka->i_pts
);
> +        es_out_Send( p_demux->out, p_sys->p_es_audio, p_blocka );
> +    }
> +
> +    return 1;
> +}
> +
>
+/*****************************************************************************
> + * Control:
> +
>
*****************************************************************************/
> +static int Control( demux_t *p_demux, int i_query, va_list args )
> +{
> +    bool *pb;
> +    int64_t *pi64;
> +
> +    switch( i_query )
> +    {
> +            /* Special for access_demux */
> +        case DEMUX_CAN_PAUSE:
> +        case DEMUX_CAN_SEEK:
> +        case DEMUX_SET_PAUSE_STATE:
> +        case DEMUX_CAN_CONTROL_PACE:
> +            pb = (bool*)va_arg( args, bool * );
> +            *pb = false;
> +            return VLC_SUCCESS;
> +
> +        case DEMUX_GET_PTS_DELAY:
> +            pi64 = (int64_t*)va_arg( args, int64_t * );
> +            *pi64 = (int64_t)DEFAULT_PTS_DELAY;
> +            return VLC_SUCCESS;

Should probably be live-caching value.

> +
> +        default:
> +            return VLC_EGENERIC;
> +    }
> +    return VLC_EGENERIC;
> +}

-- 
Rémi Denis-Courmont
http://www.remlab.net/



More information about the vlc-devel mailing list