[vlc-devel] [PATCH 1/3] qtsound: added audio capture functionality for MAC OS X
Michael Feurstein
michael.feurstein at gmail.com
Fri Oct 14 17:24:05 CEST 2011
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 | 17 +-
modules/access/Modules.am | 18 ++-
modules/access/qtsound.m | 609 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 633 insertions(+), 11 deletions(-)
create mode 100644 modules/access/qtsound.m
diff --git a/configure.ac b/configure.ac
index 925fd14..20b69de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2122,19 +2122,16 @@ 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 qtcapture (video) and qtsound (audio) module (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])
- VLC_ADD_LIBS([qtcapture], [-Wl,-framework,CoreAudio])
- VLC_ADD_LIBS([qtcapture], [-Wl,-framework,QuartzCore])
- VLC_ADD_LIBS([qtcapture], [-Wl,-framework,CoreVideo])
VLC_ADD_PLUGIN([qtcapture])
+ VLC_ADD_PLUGIN([qtsound])
fi
+AM_CONDITIONAL(HAVE_QTKIT, [test "x${enable_macosx_qtkit}" != "xno" && [test "${SYS}" = "darwin"]])
dnl
diff --git a/modules/access/Modules.am b/modules/access/Modules.am
index 45b6499..81d8e78 100644
--- a/modules/access/Modules.am
+++ b/modules/access/Modules.am
@@ -55,7 +55,6 @@ SOURCES_dvdnav = dvdnav.c
SOURCES_dvdread = dvdread.c
SOURCES_dc1394 = dc1394.c
SOURCES_pvr = pvr.c
-SOURCES_qtcapture = qtcapture.m
SOURCES_linsys_sdi = linsys/linsys_sdi.c linsys/linsys_sdi.h
SOURCES_linsys_hdsdi = \
linsys/linsys_hdsdi.c \
@@ -83,6 +82,23 @@ SOURCES_htcpcp = htcpcp.c
SOURCES_access_rar = rar/rar.c rar/rar.h rar/access.c
SOURCES_stream_filter_rar = rar/rar.c rar/rar.h rar/stream.c
+if HAVE_QTKIT
+libqtcapture_plugin_la_SOURCES = qtcapture.m
+libqtcapture_plugin_la_LIBADDD = $(AM_LIBADD)
+libqtcapture_plugin_la_LDFLAGS = -Wl,-framework,Cocoa -Wl,-framework,QTKit -Wl,-framework,CoreVideo -Wl,-framework,QuartzCore
+libqtcapture_plugin_la_DEPENDENCIES =
+
+libqtsound_plugin_la_SOURCES = qtsound.m
+libqtsound_plugin_la_LIBADD = $(AM_LIBADD)
+libqtsound_plugin_la_LDFLAGS = -Wl,-framework,Cocoa -Wl,-framework,QTKit -Wl,-framework,CoreAudio
+libqtsound_plugin_la_DEPENDENCIES =
+
+libvlc_LTLIBRARIES += \
+ libqtcapture_plugin.la \
+ libqtsound_plugin.la \
+ $(NULL)
+endif
+
libaccess_rtmp_plugin_la_SOURCES = \
rtmp/access.c \
rtmp/rtmp_amf_flv.c \
diff --git a/modules/access/qtsound.m b/modules/access/qtsound.m
new file mode 100644
index 0000000..1b7a0e1
--- /dev/null
+++ b/modules/access/qtsound.m
@@ -0,0 +1,609 @@
+/*****************************************************************************
+* 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
+{
+ demux_t *p_qtsound;
+ AudioBuffer *currentAudioBuffer;
+ UInt32 numberOfSamples;
+ date_t date;
+ mtime_t currentPts;
+ mtime_t previousPts;
+}
+- (id)initWithDemux:(demux_t *)p_demux;
+- (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection;
+- (BOOL)checkCurrentAudioBuffer;
+- (mtime_t)getCurrentPts;
+- (void *)getCurrentAudioBufferData;
+- (UInt32)getCurrentTotalDataSize;
+- (UInt32)getNumberOfSamples;
+
+ at end
+
+ at implementation VLCDecompressedAudioOutput : QTCaptureDecompressedAudioOutput
+- (id)initWithDemux:(demux_t *)p_demux
+{
+ if( self = [super init] )
+ {
+ p_qtsound = p_demux;
+ 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;
+ block_t *rawAudioData;
+ UInt32 totalDataSize = 0;
+ UInt32 count = 0;
+
+ @synchronized (self)
+ {
+ numberOfSamples = [sampleBuffer numberOfSamples];
+ date_Increment(&date,numberOfSamples);
+ currentPts = date_Get(&date);
+
+ tempAudioBufferList = [sampleBuffer audioBufferListWithOptions:0];
+ if (tempAudioBufferList->mNumberBuffers == 2)
+ {
+ /*
+ * Compute totalDataSize as sum of all data blocks in the
+ * audio buffer list:
+ */
+ for ( count = 0; count < tempAudioBufferList->mNumberBuffers; count++ )
+ {
+ totalDataSize += tempAudioBufferList->mBuffers[count].mDataByteSize;
+ }
+ /*
+ * Allocate storage for the interleaved audio data
+ */
+ rawAudioData = block_Alloc(totalDataSize * sizeof(float));
+ if (NULL == rawAudioData)
+ {
+ free(rawAudioData);
+ return;
+ }
+ }
+ else
+ {
+ msg_Err( p_qtsound, "Too many or only one channel found." );
+ return;
+ }
+
+ /*
+ * Interleave raw data (provided in two separate channels as
+ * F32L) with 2 samples per frame
+ */
+ if ( totalDataSize )
+ {
+ 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 < numberOfSamples; 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 = totalDataSize;
+ currentAudioBuffer->mData = rawAudioData;
+ }
+ }
+}
+
+- (BOOL)checkCurrentAudioBuffer
+{
+ return (currentAudioBuffer) ? 1 : 0;
+}
+
+- (mtime_t)getCurrentPts
+{
+ /* FIXME: can this getter be minimized? */
+ mtime_t pts;
+
+ if( !currentAudioBuffer || currentPts == previousPts )
+ {
+ return 0;
+ }
+
+ @synchronized (self)
+ {
+ pts = previousPts = currentPts;
+ }
+
+ return (currentAudioBuffer->mData) ? currentPts : 0;
+}
+
+- (void *)getCurrentAudioBufferData
+{
+ return currentAudioBuffer->mData;
+}
+
+- (UInt32)getCurrentTotalDataSize
+{
+ return currentAudioBuffer->mDataByteSize;
+}
+
+- (UInt32)getNumberOfSamples
+{
+ return numberOfSamples;
+}
+
+ at end
+
+/*****************************************************************************
+ * Struct
+ *****************************************************************************/
+
+struct demux_sys_t {
+ QTCaptureSession * session;
+ QTCaptureDevice * audiodevice;
+ VLCDecompressedAudioOutput * audiooutput;
+ 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;
+ char *psz_uid = NULL;
+ int audiocodec;
+ bool success;
+ NSString *qtk_curraudiodevice_uid;
+ NSAutoreleasePool *pool;
+ NSArray *myAudioDevices, *audioformat_array;
+ QTFormatDescription *audio_format;
+ QTCaptureDeviceInput *audioInput;
+ NSError *o_returnedAudioError;
+
+ /* 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 );
+ qtk_curraudiodevice_uid = [[NSString alloc] initWithFormat:@"%s", psz_uid];
+
+ 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]);
+ 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;
+ }
+ }
+
+ audioInput = nil;
+ 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] initWithDemux:p_demux];
+ 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
+ */
+ audioformat_array = [p_sys->audiodevice formatDescriptions];
+ 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 */
+ 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];
+
+ success = [p_sys->session addInput:audioInput error: &o_returnedAudioError];
+ if( !success )
+ {
+ msg_Err( p_demux, "the audio capture device could not be added to capture session (%d)", [o_returnedAudioError code] );
+ goto error;
+ }
+
+ success = [p_sys->session addOutput:p_sys->audiooutput error: &o_returnedAudioError];
+ if( !success )
+ {
+ 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;
+
+ [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;
+ NSAutoreleasePool *pool;
+
+ 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;
+ }
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ @synchronized (p_sys->audiooutput)
+ {
+ if ( [p_sys->audiooutput checkCurrentAudioBuffer] )
+ {
+ p_blocka->i_pts = [p_sys->audiooutput getCurrentPts];
+ p_blocka->p_buffer = [p_sys->audiooutput getCurrentAudioBufferData];
+ p_blocka->i_nb_samples = [p_sys->audiooutput getNumberOfSamples];
+ p_blocka->i_buffer = [p_sys->audiooutput getCurrentTotalDataSize];
+ }
+ }
+
+ 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_C(1000) * var_InheritInteger( p_demux, "live-caching" );
+ return VLC_SUCCESS;
+
+ default:
+ return VLC_EGENERIC;
+ }
+ return VLC_EGENERIC;
+}
--
1.7.4.1
More information about the vlc-devel
mailing list