123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- /*****************************************************************************
- * 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_async( _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
|