5 changed files with 2 additions and 608 deletions
@ -1,585 +0,0 @@ |
|||
/***************************************************************************** |
|||
* qtsound.m: qtkit (Mac OS X) based audio capture module |
|||
***************************************************************************** |
|||
* Copyright © 2011 VLC authors and VideoLAN |
|||
* |
|||
* Authors: Pierre d'Herbemont <pdherbemont@videolan.org> |
|||
* Gustaf Neumann <neumann@wu.ac.at> |
|||
* Michael S. Feurstein <michael.feurstein@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> |
|||
|
|||
#define QTKIT_VERSION_MIN_REQUIRED 70603 |
|||
|
|||
#import <AvailabilityMacros.h> |
|||
#import <QTKit/QTKit.h> |
|||
#import <AVFoundation/AVFoundation.h> |
|||
|
|||
#ifndef MAC_OS_X_VERSION_10_14 |
|||
@interface AVCaptureDevice (AVCaptureDeviceAuthorizationSince10_14) |
|||
|
|||
+ (void)requestAccessForMediaType:(AVMediaType)mediaType completionHandler:(void (^)(BOOL granted))handler API_AVAILABLE(macos(10.14), ios(7.0)); |
|||
|
|||
@end |
|||
#endif |
|||
|
|||
/***************************************************************************** |
|||
* 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", 0) |
|||
set_callbacks(Open, Close) |
|||
vlc_module_end () |
|||
|
|||
|
|||
/***************************************************************************** |
|||
* QTKit Bridge |
|||
*****************************************************************************/ |
|||
@interface VLCDecompressedAudioOutput : QTCaptureDecompressedAudioOutput |
|||
{ |
|||
demux_t *p_qtsound; |
|||
AudioBuffer *currentAudioBuffer; |
|||
void *rawAudioData; |
|||
UInt32 numberOfSamples; |
|||
date_t date; |
|||
vlc_tick_t currentPts; |
|||
vlc_tick_t previousPts; |
|||
} |
|||
- (id)initWithDemux:(demux_t *)p_demux; |
|||
- (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection; |
|||
- (BOOL)checkCurrentAudioBuffer; |
|||
- (void)freeAudioMem; |
|||
- (vlc_tick_t)getCurrentPts; |
|||
- (void *)getCurrentAudioBufferData; |
|||
- (UInt32)getCurrentTotalDataSize; |
|||
- (UInt32)getNumberOfSamples; |
|||
|
|||
@end |
|||
|
|||
@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, VLC_TICK_0); |
|||
currentPts = 0; |
|||
previousPts = 0; |
|||
} |
|||
return self; |
|||
} |
|||
- (void)dealloc |
|||
{ |
|||
[super dealloc]; |
|||
} |
|||
|
|||
- (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection |
|||
{ |
|||
AudioBufferList *tempAudioBufferList; |
|||
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 = malloc(totalDataSize); |
|||
if (NULL == rawAudioData) { |
|||
msg_Err(p_qtsound, "Raw audiodata could not be allocated"); |
|||
return; |
|||
} |
|||
} else { |
|||
msg_Err(p_qtsound, "Too many or only one channel found: %i.", |
|||
tempAudioBufferList->mNumberBuffers); |
|||
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++ = *b2Ptr++; |
|||
} |
|||
|
|||
if (currentAudioBuffer == nil) { |
|||
currentAudioBuffer = (AudioBuffer *)malloc(sizeof(AudioBuffer)); |
|||
if (NULL == currentAudioBuffer) { |
|||
msg_Err(p_qtsound, "AudioBuffer could not be allocated."); |
|||
return; |
|||
} |
|||
} |
|||
currentAudioBuffer->mNumberChannels = 2; |
|||
currentAudioBuffer->mDataByteSize = totalDataSize; |
|||
currentAudioBuffer->mData = rawAudioData; |
|||
} |
|||
} |
|||
} |
|||
|
|||
- (BOOL)checkCurrentAudioBuffer |
|||
{ |
|||
return (currentAudioBuffer) ? 1 : 0; |
|||
} |
|||
|
|||
- (void)freeAudioMem |
|||
{ |
|||
FREENULL(rawAudioData); |
|||
} |
|||
|
|||
- (vlc_tick_t)getCurrentPts |
|||
{ |
|||
/* FIXME: can this getter be minimized? */ |
|||
vlc_tick_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; |
|||
} |
|||
|
|||
@end |
|||
|
|||
/***************************************************************************** |
|||
* Struct |
|||
*****************************************************************************/ |
|||
|
|||
typedef struct demux_sys_t { |
|||
QTCaptureSession * session; |
|||
QTCaptureDevice * audiodevice; |
|||
VLCDecompressedAudioOutput * audiooutput; |
|||
es_out_id_t *p_es_audio; |
|||
} demux_sys_t; |
|||
|
|||
/***************************************************************************** |
|||
* 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; |
|||
NSArray *myAudioDevices, *audioformat_array; |
|||
QTFormatDescription *audio_format; |
|||
QTCaptureDeviceInput *audioInput; |
|||
NSError *o_returnedAudioError; |
|||
|
|||
if (p_demux->out == NULL) |
|||
return VLC_EGENERIC; |
|||
|
|||
@autoreleasepool { |
|||
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]; |
|||
|
|||
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) { |
|||
vlc_dialog_display_error(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; |
|||
} |
|||
unsigned iaudio; |
|||
for (iaudio = 0; iaudio < [myAudioDevices count]; iaudio++) { |
|||
QTCaptureDevice *qtk_audioDevice; |
|||
qtk_audioDevice = [myAudioDevices objectAtIndex:iaudio]; |
|||
msg_Dbg(p_demux, "qtsound audio %u/%lu localizedDisplayName: %s uniqueID: %s", |
|||
iaudio, [myAudioDevices count], |
|||
[[qtk_audioDevice localizedDisplayName] UTF8String], |
|||
[[qtk_audioDevice uniqueID] UTF8String]); |
|||
if ([[[qtk_audioDevice uniqueID] 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) { |
|||
vlc_dialog_display_error(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 (%ld)", [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; |
|||
} |
|||
|
|||
if (@available(macOS 10.14, *)) { |
|||
msg_Dbg(p_demux, "Check user consent for access to the audio device"); |
|||
|
|||
dispatch_semaphore_t sema = dispatch_semaphore_create(0); |
|||
__block bool accessGranted = NO; |
|||
[AVCaptureDevice requestAccessForMediaType: AVMediaTypeAudio completionHandler:^(BOOL granted) { |
|||
accessGranted = granted; |
|||
dispatch_semaphore_signal(sema); |
|||
} ]; |
|||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); |
|||
dispatch_release(sema); |
|||
if (!accessGranted) { |
|||
msg_Err(p_demux, "Can't use the audio device as access has not been granted by the user"); |
|||
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; |
|||
/* |
|||
* 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 / 8); |
|||
audiofmt.i_bitrate = audiofmt.audio.i_channels * audiofmt.audio.i_rate * audiofmt.audio.i_bitspersample; |
|||
|
|||
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 (%ld)", [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 (%ld)", [o_returnedAudioError code]); |
|||
goto error; |
|||
} |
|||
|
|||
[p_sys->session startRunning]; |
|||
|
|||
/* Set up p_demux */ |
|||
p_demux->pf_demux = Demux; |
|||
p_demux->pf_control = Control; |
|||
|
|||
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]; |
|||
|
|||
msg_Dbg(p_demux, "QTSound: We have an audio device ready!"); |
|||
|
|||
return VLC_SUCCESS; |
|||
error: |
|||
[audioInput release]; |
|||
|
|||
free(p_sys); |
|||
|
|||
return VLC_EGENERIC; |
|||
} |
|||
} |
|||
|
|||
/***************************************************************************** |
|||
* Close: destroy interface |
|||
*****************************************************************************/ |
|||
static void Close(vlc_object_t *p_this) |
|||
{ |
|||
@autoreleasepool { |
|||
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); |
|||
} |
|||
} |
|||
|
|||
/***************************************************************************** |
|||
* Demux: |
|||
*****************************************************************************/ |
|||
static int Demux(demux_t *p_demux) |
|||
{ |
|||
demux_sys_t *p_sys = p_demux->p_sys; |
|||
block_t *p_blocka = nil; |
|||
|
|||
@autoreleasepool { |
|||
@synchronized (p_sys->audiooutput) { |
|||
if ([p_sys->audiooutput checkCurrentAudioBuffer]) { |
|||
unsigned i_buffer_size = [p_sys->audiooutput getCurrentTotalDataSize]; |
|||
p_blocka = block_Alloc(i_buffer_size); |
|||
|
|||
if(!p_blocka) { |
|||
msg_Err(p_demux, "cannot get audio block"); |
|||
return 0; |
|||
} |
|||
|
|||
memcpy(p_blocka->p_buffer, [p_sys->audiooutput getCurrentAudioBufferData], i_buffer_size); |
|||
p_blocka->i_nb_samples = [p_sys->audiooutput getNumberOfSamples]; |
|||
p_blocka->i_pts = [p_sys->audiooutput getCurrentPts]; |
|||
|
|||
[p_sys->audiooutput freeAudioMem]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (p_blocka) { |
|||
if (!p_blocka->i_pts) { |
|||
block_Release(p_blocka); |
|||
|
|||
// Nothing to transfer yet, just forget |
|||
vlc_tick_sleep(VLC_HARD_MIN_SLEEP); |
|||
return 1; |
|||
} |
|||
|
|||
es_out_SetPCR(p_demux->out, 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; |
|||
|
|||
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: |
|||
*va_arg(args, vlc_tick_t *) = |
|||
VLC_TICK_FROM_MS(var_InheritInteger(p_demux, "live-caching")); |
|||
return VLC_SUCCESS; |
|||
|
|||
default: |
|||
return VLC_EGENERIC; |
|||
} |
|||
return VLC_EGENERIC; |
|||
} |
|||
Loading…
Reference in new issue