Skip to content

Instantly share code, notes, and snippets.

@tmm1
Created November 19, 2015 05:20
Show Gist options
  • Save tmm1/a54d4fef79f2c2b3f0ee to your computer and use it in GitHub Desktop.
Save tmm1/a54d4fef79f2c2b3f0ee to your computer and use it in GitHub Desktop.
wip vlc avplayer audio_output module
From: Aman <aman@tmm1.net>
Date: Fri Aug 10 16:02:07 2012 +0200
Subject: add AVPlayer audio output module
---
diff --git a/extras/package/ios/build.sh b/extras/package/ios/build.sh
index c2a1462..3070c02 100755
--- a/extras/package/ios/build.sh
+++ b/extras/package/ios/build.sh
@@ -453,7 +453,6 @@ speex_resampler
remoteosd
magnify
gradient
-tospdif
dtstofloat32
logger
visual
diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index 1644fde..507452c 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -59,6 +59,7 @@ $Id$
* avformat: libavformat demuxer
* avi: AVI file stream demuxer
* avio: Access and Stream output module using libavformat network
+ * avplayer_ios: AVPlayer output plugin for iOS
* ball: Augmented reality ball video filter module
* bandlimited_resampler: Bandlimited interpolation audio resampler
* blend: a picture filter that blends two pictures
diff --git a/modules/audio_output/Makefile.am b/modules/audio_output/Makefile.am
index 5850947..cf20295 100644
--- a/modules/audio_output/Makefile.am
+++ b/modules/audio_output/Makefile.am
@@ -114,6 +114,16 @@ if HAVE_TVOS
aout_LTLIBRARIES += libaudiounit_ios_plugin.la
endif
+libavplayer_ios_plugin_la_SOURCES = audio_output/avplayer_ios.m \
+ audio_output/TPCircularBuffer.h audio_output/TPCircularBuffer.c
+libavplayer_ios_plugin_la_LDFLAGS = $(AM_LDFLAGS) -Wl,-framework,CoreAudio,-framework,AudioUnit,-framework,AudioToolbox,-framework,CoreServices,-framework,UIKit,-framework,AVFoundation -rpath '$(aoutdir)'
+if HAVE_IOS
+aout_LTLIBRARIES += libavplayer_ios_plugin.la
+endif
+if HAVE_TVOS
+aout_LTLIBRARIES += libavplayer_ios_plugin.la
+endif
+
libaudioqueue_plugin_la_SOURCES = audio_output/audioqueue.c
libaudioqueue_plugin_la_LDFLAGS = $(AM_LDFLAGS) -Wl,-framework,CoreAudio,-framework,AudioUnit,-framework,AudioToolbox,-framework,CoreServices -rpath '$(aoutdir)'
EXTRA_LTLIBRARIES += libaudioqueue_plugin.la
diff --git a/modules/audio_output/avplayer_ios.m b/modules/audio_output/avplayer_ios.m
new file mode 100644
index 0000000..f67f6a7
--- /dev/null
+++ b/modules/audio_output/avplayer_ios.m
@@ -0,0 +1,306 @@
+/*****************************************************************************
+ * avplayer_ios.m: AVPlayer output plugin for iOS
+ *****************************************************************************
+ * Copyright (C) 2012 - 2015 VLC authors and VideoLAN
+ * $Id$
+ *
+ * Authors: Aman Gupta <vlc at tmm1 dot net>
+ *
+ * This program 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 program 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#pragma mark includes
+
+#ifdef HAVE_CONFIG_H
+# import "config.h"
+#endif
+
+#import <vlc_common.h>
+#import <vlc_plugin.h>
+#import <vlc_aout.h>
+
+#import <AVFoundation/AVFoundation.h>
+#import <mach/mach_time.h>
+
+#import "TPCircularBuffer.h"
+
+#pragma mark -
+#pragma mark private declarations
+
+@interface ResourceLoader : NSObject <AVAssetResourceLoaderDelegate>
+@property (nonatomic) struct aout_sys_t *p_sys;
+@end
+
+/*****************************************************************************
+ * aout_sys_t: private audio output method descriptor
+ *****************************************************************************
+ * This structure is part of the audio output thread descriptor.
+ * It describes the CoreAudio specific properties of an output thread.
+ *****************************************************************************/
+struct aout_sys_t
+{
+ TPCircularBuffer circular_buffer; /* circular buffer to swap the audio data */
+
+ AVPlayer *player;
+ ResourceLoader *delegate;
+
+ int i_rate; /* media sample rate */
+ int i_bytes_per_sample;
+
+ bool b_paused;
+
+ vlc_mutex_t lock;
+ vlc_cond_t cond;
+};
+
+#pragma mark -
+#pragma mark local prototypes & module descriptor
+
+static int Open (vlc_object_t *);
+static void Close (vlc_object_t *);
+static int Start (audio_output_t *, audio_sample_format_t *);
+static int StartAnalog (audio_output_t *, audio_sample_format_t *);
+static void Stop (audio_output_t *);
+
+static void Play (audio_output_t *, block_t *);
+static void Pause (audio_output_t *, bool, mtime_t);
+static int MuteSet (audio_output_t *aout, bool mute);
+static void Flush (audio_output_t *, bool);
+static int TimeGet (audio_output_t *, mtime_t *);
+static OSStatus RenderCallback (vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
+ UInt32 , UInt32, AudioBufferList *);
+
+vlc_module_begin ()
+ set_shortname("avplayer_ios")
+ set_description(N_("AVPlayer output for iOS"))
+ set_capability("audio output", 111)
+ set_category(CAT_AUDIO)
+ set_subcategory(SUBCAT_AUDIO_AOUT)
+ set_callbacks(Open, Close)
+vlc_module_end ()
+
+#pragma mark -
+#pragma mark initialization
+
+static int Open(vlc_object_t *obj)
+{
+ audio_output_t *aout = (audio_output_t *)obj;
+ aout_sys_t *sys = malloc(sizeof (*sys));
+
+ if (unlikely(sys == NULL))
+ return VLC_ENOMEM;
+
+ vlc_mutex_init(&sys->lock);
+ vlc_cond_init(&sys->cond);
+ sys->b_paused = false;
+
+ aout->sys = sys;
+ aout->start = Start;
+ aout->stop = Stop;
+
+ return VLC_SUCCESS;
+}
+
+static void Close(vlc_object_t *obj)
+{
+ audio_output_t *aout = (audio_output_t *)obj;
+ aout_sys_t *sys = aout->sys;
+
+ vlc_mutex_destroy(&sys->lock);
+ vlc_cond_destroy(&sys->cond);
+
+ free(sys);
+}
+
+static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
+{
+ struct aout_sys_t *p_sys = NULL;
+
+ p_sys = p_aout->sys;
+ p_sys->i_bytes_per_sample = 0;
+ p_sys->i_rate = fmt->i_rate;
+
+ aout_FormatPrint(p_aout, "VLC is looking for:", fmt);
+ if (!AOUT_FMT_SPDIF(fmt))
+ return VLC_EGENERIC;
+
+ /* setup circular buffer */
+ TPCircularBufferInit(&p_sys->circular_buffer, 200 * AOUT_SPDIF_SIZE);
+
+ p_sys->delegate = [ResourceLoader new];
+ p_sys->delegate.p_sys = p_sys;
+
+ NSURL *videoURL = [NSURL URLWithString:@"streaming://fake/out.ac3"];
+ AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
+ //[asset.resourceLoader setDelegate:p_sys->delegate queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
+ [asset.resourceLoader setDelegate:p_sys->delegate queue:dispatch_get_main_queue()];
+
+ AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
+ //[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:NULL];
+ p_sys->player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
+
+ p_aout->play = Play;
+ p_aout->flush = Flush;
+ p_aout->mute_set = MuteSet;
+ p_aout->time_get = TimeGet;
+ p_aout->pause = Pause;
+
+ [p_sys->player play];
+
+ return VLC_SUCCESS;
+}
+
+static void Stop(audio_output_t *p_aout)
+{
+ struct aout_sys_t *p_sys = p_aout->sys;
+ OSStatus status;
+
+ [p_sys->player pause];
+ p_sys->player = nil;
+ p_sys->i_bytes_per_sample = 0;
+
+ /* clean-up circular buffer */
+ TPCircularBufferCleanup(&p_sys->circular_buffer);
+}
+
+#pragma mark -
+#pragma mark actual playback
+
+static void Play (audio_output_t * p_aout, block_t * p_block)
+{
+ struct aout_sys_t *p_sys = p_aout->sys;
+
+ if (p_block->i_nb_samples > 0) {
+ /* move data to buffer */
+ if (unlikely(!TPCircularBufferProduceBytes(&p_sys->circular_buffer, p_block->p_buffer, p_block->i_buffer)))
+ msg_Warn(p_aout, "Audio buffer was dropped");
+
+ if (!p_sys->i_bytes_per_sample)
+ p_sys->i_bytes_per_sample = p_block->i_buffer / p_block->i_nb_samples;
+ }
+
+ block_Release(p_block);
+}
+
+static void Pause (audio_output_t *p_aout, bool pause, mtime_t date)
+{
+ struct aout_sys_t * p_sys = p_aout->sys;
+ VLC_UNUSED(date);
+
+ vlc_mutex_lock(&p_sys->lock);
+ p_sys->b_paused = pause;
+ vlc_mutex_unlock(&p_sys->lock);
+
+ if (p_sys->player == NULL) {
+ return;
+ }
+
+ [p_sys->player pause];
+}
+
+static int MuteSet(audio_output_t *p_aout, bool mute)
+{
+ return VLC_EGENERIC;
+}
+
+static void Flush(audio_output_t *p_aout, bool wait)
+{
+ struct aout_sys_t *p_sys = p_aout->sys;
+
+ int32_t availableBytes;
+ vlc_mutex_lock(&p_sys->lock);
+ TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+
+ if (wait) {
+ while (availableBytes > 0) {
+ vlc_cond_wait(&p_sys->cond, &p_sys->lock);
+ TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+ }
+ } else {
+ /* flush circular buffer if data is left */
+ if (availableBytes > 0)
+ TPCircularBufferClear(&p_aout->sys->circular_buffer);
+ }
+
+ vlc_mutex_unlock(&p_sys->lock);
+}
+
+static int TimeGet(audio_output_t *p_aout, mtime_t *delay)
+{
+ struct aout_sys_t * p_sys = p_aout->sys;
+
+ if (!p_sys->i_bytes_per_sample)
+ return -1;
+
+ int32_t availableBytes;
+ TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+
+ *delay = (availableBytes / p_sys->i_bytes_per_sample) * CLOCK_FREQ / p_sys->i_rate;
+
+ return 0;
+}
+
+@implementation ResourceLoader
+- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest{
+ AVAssetResourceLoadingContentInformationRequest* contentRequest = loadingRequest.contentInformationRequest;
+ if (contentRequest) {
+ contentRequest.contentType = @"public.ac3-audio";
+ contentRequest.contentLength = 2*1024*1024*1024;
+ contentRequest.byteRangeAccessSupported = YES;
+ NSLog(@"contentRequest: %@", contentRequest);
+ }
+
+ AVAssetResourceLoadingDataRequest* dataRequest = loadingRequest.dataRequest;
+ if (dataRequest) {
+ NSLog(@"dataRequest: %@", dataRequest);
+ //dispatch_async(dispatch_get_main_queue(), ^{
+ NSInteger reqLen = dataRequest.requestedLength;
+ if (reqLen == 2) {
+ [dataRequest respondWithData:[NSData dataWithBytes:"\vw" length:2]];
+ [loadingRequest finishLoading];
+ } else {
+ int bytesRequested = (int)reqLen;
+ struct aout_sys_t *p_sys = self.p_sys;
+
+ vlc_mutex_lock(&p_sys->lock);
+ /* Pull audio from buffer */
+ int32_t availableBytes;
+ void *buffer = TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+
+ /* check if we have enough data */
+ if (!availableBytes || p_sys->b_paused) {
+ /* return an empty buffer so silence is played until we have data */
+ } else {
+ int32_t bytesToCopy = __MIN(bytesRequested, availableBytes);
+
+ if (likely(bytesToCopy > 0)) {
+ NSData *data = [NSData dataWithBytes:buffer length:bytesToCopy];
+ [dataRequest respondWithData:data];
+ NSLog(@"sending %du bytes", [data length]);
+ TPCircularBufferConsume(&p_sys->circular_buffer, bytesToCopy);
+ }
+ }
+
+ vlc_cond_signal(&p_sys->cond);
+ vlc_mutex_unlock(&p_sys->lock);
+
+ [loadingRequest finishLoading];
+ }
+ //});
+ }
+
+ return YES;
+}
+@end
diff --git a/modules/codec/a52.c b/modules/codec/a52.c
index 7450d6b..7ee1cce 100644
--- a/modules/codec/a52.c
+++ b/modules/codec/a52.c
@@ -150,7 +150,7 @@ static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
static int OpenDecoder( vlc_object_t *p_this )
{
/* HACK: Don't use this codec if we don't have an a52 audio filter */
- if( !module_exists( "a52tofloat32" ) )
+ if( !module_exists( "a52tofloat32" ) && !module_exists("a52tospdif") )
return VLC_EGENERIC;
return OpenCommon( p_this, false );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment