|
@@ -0,0 +1,143 @@
|
|
|
+/*****************************************************************************
|
|
|
+ * VLCTranscoder.m: VLCKit.framework VLCTranscoder implementation
|
|
|
+ *****************************************************************************
|
|
|
+ * Copyright (C) 2018 Carola Nitz
|
|
|
+ * Copyright (C) 2018 VLC authors and VideoLAN
|
|
|
+ * $Id$
|
|
|
+ *
|
|
|
+ * Authors: Carola Nitz <caro # videolan.org>
|
|
|
+ *
|
|
|
+ * 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.
|
|
|
+ *****************************************************************************/
|
|
|
+#import "VLCTranscoder.h"
|
|
|
+
|
|
|
+#import "VLCEventManager.h"
|
|
|
+#import "VLCLibrary.h"
|
|
|
+#import "VLCLibVLCBridging.h"
|
|
|
+
|
|
|
+#include <vlc/vlc.h>
|
|
|
+
|
|
|
+@interface VLCTranscoder()
|
|
|
+{
|
|
|
+ libvlc_media_player_t *_p_mp; //player instance used for transcoding
|
|
|
+ dispatch_queue_t _libVLCTranscoderQueue;
|
|
|
+}
|
|
|
+- (void)registerObserversForMuxWithPlayer:(libvlc_media_player_t *)player;
|
|
|
+- (void)unregisterObserversForMuxWithPlayer:(libvlc_media_player_t *)player;
|
|
|
+@end
|
|
|
+
|
|
|
+@implementation VLCTranscoder
|
|
|
+
|
|
|
+- (instancetype)init
|
|
|
+{
|
|
|
+ if (self = [super init]) {
|
|
|
+ _libVLCTranscoderQueue = dispatch_queue_create("libVLCTranscoderQueue", DISPATCH_QUEUE_SERIAL);
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+- (BOOL)reencodeAndMuxSRTFile:(NSString *)srtPath toMP4File:(NSString *)mp4Path outputPath:(NSString *)outPath
|
|
|
+{
|
|
|
+ libvlc_media_t* p_media = libvlc_media_new_path([[VLCLibrary sharedLibrary] instance], [mp4Path UTF8String]);
|
|
|
+ if (p_media == NULL) {
|
|
|
+ NSAssert(0, @"p_media wasn't allocated");
|
|
|
+ return NO;
|
|
|
+ }
|
|
|
+ NSString *transcodingOptions = [NSString stringWithFormat:@":sout=#transcode{venc={module=avcodec{codec=h264_videotoolbox}, vcodec=h264},venc={module=vpx{quality-mode=2},vcodec=VP80},samplerate=44100,soverlay}:file{dst='%@',mux=mkv}", outPath];
|
|
|
+ libvlc_media_add_option(p_media, [[NSString stringWithFormat:@"--sub-file=%@", srtPath] UTF8String]);
|
|
|
+ libvlc_media_add_option(p_media, [transcodingOptions UTF8String]);
|
|
|
+
|
|
|
+ _p_mp = libvlc_media_player_new_from_media( p_media );
|
|
|
+ if (_p_mp == NULL) {
|
|
|
+ NSAssert(0, @"_p_mp wasn't allocated");
|
|
|
+ return NO;
|
|
|
+ }
|
|
|
+
|
|
|
+ [self registerObserversForMuxWithPlayer:_p_mp];
|
|
|
+ BOOL canPlay = libvlc_media_player_play( _p_mp ) == 0;
|
|
|
+ if (!canPlay) {
|
|
|
+ NSAssert(0, @"playback failed");
|
|
|
+ [self unregisterObserversForMuxWithPlayer:_p_mp];
|
|
|
+ return NO;
|
|
|
+ }
|
|
|
+ return canPlay;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)registerObserversForMuxWithPlayer:(libvlc_media_player_t *)player
|
|
|
+{
|
|
|
+ __block libvlc_event_manager_t * p_em = libvlc_media_player_event_manager(player);
|
|
|
+ if (!p_em)
|
|
|
+ return;
|
|
|
+ CFBridgingRetain(self);
|
|
|
+ dispatch_sync(_libVLCTranscoderQueue,^{
|
|
|
+ libvlc_event_attach(p_em, libvlc_MediaPlayerPaused,
|
|
|
+ HandleMuxMediaInstanceStateChanged, (__bridge void *)(self));
|
|
|
+ libvlc_event_attach(p_em, libvlc_MediaPlayerStopped,
|
|
|
+ HandleMuxMediaInstanceStateChanged, (__bridge void *)(self));
|
|
|
+ libvlc_event_attach(p_em, libvlc_MediaPlayerEncounteredError,
|
|
|
+ HandleMuxMediaInstanceStateChanged, (__bridge void *)(self));
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+- (void)unregisterObserversForMuxWithPlayer:(libvlc_media_player_t *)player
|
|
|
+{
|
|
|
+ libvlc_event_manager_t * p_em = libvlc_media_player_event_manager(player);
|
|
|
+ if (!p_em)
|
|
|
+ return;
|
|
|
+ dispatch_sync(_libVLCTranscoderQueue,^{
|
|
|
+ libvlc_event_detach(p_em, libvlc_MediaPlayerStopped,
|
|
|
+ HandleMuxMediaInstanceStateChanged, (__bridge void *)(self));
|
|
|
+ libvlc_event_detach(p_em, libvlc_MediaPlayerPaused,
|
|
|
+ HandleMuxMediaInstanceStateChanged, (__bridge void *)(self));
|
|
|
+ libvlc_event_detach(p_em, libvlc_MediaPlayerEncounteredError,
|
|
|
+ HandleMuxMediaInstanceStateChanged, (__bridge void *)(self));
|
|
|
+ });
|
|
|
+ CFBridgingRelease((__bridge CFTypeRef _Nullable)(self));
|
|
|
+}
|
|
|
+
|
|
|
+- (void)mediaPlayerStateChangeForMux:(NSNumber *)newState
|
|
|
+{
|
|
|
+ if (_p_mp) {
|
|
|
+ [self unregisterObserversForMuxWithPlayer:_p_mp];
|
|
|
+ libvlc_media_player_stop( _p_mp );
|
|
|
+ if (self.delegate && [self.delegate respondsToSelector:@selector(transcode:finishedSucessfully:)]) {
|
|
|
+ BOOL success = ![newState isEqualToNumber: @(VLCMediaPlayerStateError)];
|
|
|
+ [self.delegate transcode:self finishedSucessfully:success];
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void HandleMuxMediaInstanceStateChanged(const libvlc_event_t * event, void * self)
|
|
|
+{
|
|
|
+ VLCMediaPlayerState newState;
|
|
|
+ if (event->type == libvlc_MediaPlayerPaused) {
|
|
|
+ newState = VLCMediaPlayerStatePaused;
|
|
|
+ } else if(event->type == libvlc_MediaPlayerStopped) {
|
|
|
+ newState = VLCMediaPlayerStateStopped;
|
|
|
+ } else {
|
|
|
+ newState = VLCMediaPlayerStateError;
|
|
|
+ }
|
|
|
+ @autoreleasepool {
|
|
|
+ [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self)
|
|
|
+ withMethod:@selector(mediaPlayerStateChangeForMux:)
|
|
|
+ withArgumentAsObject:@(newState)];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)dealloc
|
|
|
+{
|
|
|
+ libvlc_media_player_release(_p_mp);
|
|
|
+}
|
|
|
+@end
|