new api: getMediaInformation for ios

This commit is contained in:
Taner Sener
2018-10-23 17:07:53 +03:00
parent 998d3bfa37
commit 48645800ec
15 changed files with 2495 additions and 30 deletions
+5
View File
@@ -2,3 +2,8 @@
/Makefile
/config.status
/configure.tmp
/.deps/
/.libs/
*.trs
/unittests
/test-driver
+5 -5
View File
@@ -9331,20 +9331,20 @@ fi
$as_echo "$lt_cv_ld_force_load" >&6; }
case $host_os in
rhapsody* | darwin1.[012])
_lt_dar_allow_undefined='' ;;
_lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='' ;;
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
darwin*) # darwin 5.x on
# if running on 10.5 or later, the deployment target defaults
# to the OS version, if on x86, and 10.4, the deployment
# target defaults to 10.4. Don't you love it?
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[91]*)
_lt_dar_allow_undefined='${wl}dynamic_lookup' ;;
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
10.[012][,.]*)
_lt_dar_allow_undefined='' ;;
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
10.*)
_lt_dar_allow_undefined='${wl}dynamic_lookup' ;;
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
esac
+8 -2
View File
@@ -10,21 +10,27 @@ libmobileffmpeg_la_SOURCES = \
fftools_ffmpeg_hw.c \
fftools_ffmpeg_opt.c \
fftools_ffmpeg_videotoolbox.c \
MediaInformation.m \
MediaInformationParser.m \
MobileFFmpeg.m \
MobileFFmpegConfig.m \
mobileffmpeg_exception.m \
Statistics.m
Statistics.m \
StreamInformation.m
include_HEADERS = \
ArchDetect.h \
fftools_cmdutils.h \
fftools_ffmpeg.h \
LogDelegate.h \
MediaInformation.h \
MediaInformationParser.h \
MobileFFmpeg.h \
MobileFFmpegConfig.h \
mobileffmpeg_exception.h \
Statistics.h \
StatisticsDelegate.h
StatisticsDelegate.h \
StreamInformation.h
libmobileffmpeg_la_CFLAGS = $(CFLAGS)
libmobileffmpeg_la_OBJCFLAGS = $(CFLAGS)
+45 -3
View File
@@ -139,10 +139,13 @@ am_libmobileffmpeg_la_OBJECTS = libmobileffmpeg_la-ArchDetect.lo \
libmobileffmpeg_la-fftools_ffmpeg_hw.lo \
libmobileffmpeg_la-fftools_ffmpeg_opt.lo \
libmobileffmpeg_la-fftools_ffmpeg_videotoolbox.lo \
libmobileffmpeg_la-MediaInformation.lo \
libmobileffmpeg_la-MediaInformationParser.lo \
libmobileffmpeg_la-MobileFFmpeg.lo \
libmobileffmpeg_la-MobileFFmpegConfig.lo \
libmobileffmpeg_la-mobileffmpeg_exception.lo \
libmobileffmpeg_la-Statistics.lo
libmobileffmpeg_la-Statistics.lo \
libmobileffmpeg_la-StreamInformation.lo
libmobileffmpeg_la_OBJECTS = $(am_libmobileffmpeg_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -168,9 +171,12 @@ DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/libmobileffmpeg_la-ArchDetect.Plo \
./$(DEPDIR)/libmobileffmpeg_la-MediaInformation.Plo \
./$(DEPDIR)/libmobileffmpeg_la-MediaInformationParser.Plo \
./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpeg.Plo \
./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpegConfig.Plo \
./$(DEPDIR)/libmobileffmpeg_la-Statistics.Plo \
./$(DEPDIR)/libmobileffmpeg_la-StreamInformation.Plo \
./$(DEPDIR)/libmobileffmpeg_la-fftools_cmdutils.Plo \
./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg.Plo \
./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg_filter.Plo \
@@ -375,21 +381,27 @@ libmobileffmpeg_la_SOURCES = \
fftools_ffmpeg_hw.c \
fftools_ffmpeg_opt.c \
fftools_ffmpeg_videotoolbox.c \
MediaInformation.m \
MediaInformationParser.m \
MobileFFmpeg.m \
MobileFFmpegConfig.m \
mobileffmpeg_exception.m \
Statistics.m
Statistics.m \
StreamInformation.m
include_HEADERS = \
ArchDetect.h \
fftools_cmdutils.h \
fftools_ffmpeg.h \
LogDelegate.h \
MediaInformation.h \
MediaInformationParser.h \
MobileFFmpeg.h \
MobileFFmpegConfig.h \
mobileffmpeg_exception.h \
Statistics.h \
StatisticsDelegate.h
StatisticsDelegate.h \
StreamInformation.h
libmobileffmpeg_la_CFLAGS = $(CFLAGS)
libmobileffmpeg_la_OBJCFLAGS = $(CFLAGS)
@@ -474,9 +486,12 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-ArchDetect.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-MediaInformation.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-MediaInformationParser.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpeg.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpegConfig.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-Statistics.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-StreamInformation.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-fftools_cmdutils.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg_filter.Plo@am__quote@ # am--include-marker
@@ -588,6 +603,20 @@ libmobileffmpeg_la-ArchDetect.lo: ArchDetect.m
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libmobileffmpeg_la-ArchDetect.lo `test -f 'ArchDetect.m' || echo '$(srcdir)/'`ArchDetect.m
libmobileffmpeg_la-MediaInformation.lo: MediaInformation.m
@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -MT libmobileffmpeg_la-MediaInformation.lo -MD -MP -MF $(DEPDIR)/libmobileffmpeg_la-MediaInformation.Tpo -c -o libmobileffmpeg_la-MediaInformation.lo `test -f 'MediaInformation.m' || echo '$(srcdir)/'`MediaInformation.m
@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmobileffmpeg_la-MediaInformation.Tpo $(DEPDIR)/libmobileffmpeg_la-MediaInformation.Plo
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='MediaInformation.m' object='libmobileffmpeg_la-MediaInformation.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libmobileffmpeg_la-MediaInformation.lo `test -f 'MediaInformation.m' || echo '$(srcdir)/'`MediaInformation.m
libmobileffmpeg_la-MediaInformationParser.lo: MediaInformationParser.m
@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -MT libmobileffmpeg_la-MediaInformationParser.lo -MD -MP -MF $(DEPDIR)/libmobileffmpeg_la-MediaInformationParser.Tpo -c -o libmobileffmpeg_la-MediaInformationParser.lo `test -f 'MediaInformationParser.m' || echo '$(srcdir)/'`MediaInformationParser.m
@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmobileffmpeg_la-MediaInformationParser.Tpo $(DEPDIR)/libmobileffmpeg_la-MediaInformationParser.Plo
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='MediaInformationParser.m' object='libmobileffmpeg_la-MediaInformationParser.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libmobileffmpeg_la-MediaInformationParser.lo `test -f 'MediaInformationParser.m' || echo '$(srcdir)/'`MediaInformationParser.m
libmobileffmpeg_la-MobileFFmpeg.lo: MobileFFmpeg.m
@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -MT libmobileffmpeg_la-MobileFFmpeg.lo -MD -MP -MF $(DEPDIR)/libmobileffmpeg_la-MobileFFmpeg.Tpo -c -o libmobileffmpeg_la-MobileFFmpeg.lo `test -f 'MobileFFmpeg.m' || echo '$(srcdir)/'`MobileFFmpeg.m
@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmobileffmpeg_la-MobileFFmpeg.Tpo $(DEPDIR)/libmobileffmpeg_la-MobileFFmpeg.Plo
@@ -616,6 +645,13 @@ libmobileffmpeg_la-Statistics.lo: Statistics.m
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libmobileffmpeg_la-Statistics.lo `test -f 'Statistics.m' || echo '$(srcdir)/'`Statistics.m
libmobileffmpeg_la-StreamInformation.lo: StreamInformation.m
@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -MT libmobileffmpeg_la-StreamInformation.lo -MD -MP -MF $(DEPDIR)/libmobileffmpeg_la-StreamInformation.Tpo -c -o libmobileffmpeg_la-StreamInformation.lo `test -f 'StreamInformation.m' || echo '$(srcdir)/'`StreamInformation.m
@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmobileffmpeg_la-StreamInformation.Tpo $(DEPDIR)/libmobileffmpeg_la-StreamInformation.Plo
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='StreamInformation.m' object='libmobileffmpeg_la-StreamInformation.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmobileffmpeg_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libmobileffmpeg_la-StreamInformation.lo `test -f 'StreamInformation.m' || echo '$(srcdir)/'`StreamInformation.m
mostlyclean-libtool:
-rm -f *.lo
@@ -772,9 +808,12 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
distclean: distclean-am
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-ArchDetect.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MediaInformation.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MediaInformationParser.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpeg.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpegConfig.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-Statistics.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-StreamInformation.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-fftools_cmdutils.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg_filter.Plo
@@ -828,9 +867,12 @@ installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-ArchDetect.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MediaInformation.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MediaInformationParser.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpeg.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-MobileFFmpegConfig.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-Statistics.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-StreamInformation.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-fftools_cmdutils.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg.Plo
-rm -f ./$(DEPDIR)/libmobileffmpeg_la-fftools_ffmpeg_filter.Plo
+139
View File
@@ -0,0 +1,139 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg 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 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Foundation/Foundation.h>
#include "StreamInformation.h"
@interface MediaInformation : NSObject
- (instancetype)init;
/**
* Returns format.
*
* \return media format
*/
- (NSString*)getFormat;
/**
* Sets media format.
*
* \param media format
*/
- (void)setFormat:(NSString*)format;
/**
* Returns path.
*
* \return media path
*/
- (NSString*)getPath;
/**
* Sets media path.
*
* \param media path
*/
- (void)setPath:(NSString*)path;
/**
* Returns duration.
*
* \return media duration in milliseconds
*/
- (NSNumber*)getDuration;
/**
* Sets media duration.
*
* \param media duration in milliseconds
*/
- (void)setDuration:(NSNumber*) duration;
/**
* Returns start time.
*
* \return media start time in milliseconds
*/
- (NSNumber*)getStartTime;
/**
* Sets media start time.
*
* \param media start time in milliseconds
*/
- (void)setStartTime:(NSNumber*)startTime;
/**
* Returns bitrate.
*
* \return media bitrate in kb/s
*/
- (NSNumber*)getBitrate;
/**
* Sets bitrate.
*
* \param media bitrate in kb/s
*/
- (void)setBitrate:(NSNumber*) bitrate;
/**
* Returns unparsed media information.
*
* \return unparsed media information data
*/
- (NSString*)getRawInformation;
/**
* Sets unparsed media information.
*
* \param unparsed media information data
*/
- (void)setRawInformation:(NSString*)rawInformation;
/**
* Adds metadata.
*
* \param metadata key and value
*/
- (void)addMetadata:(NSString*)key :(NSString*)value;
/**
* Returns all metadata entries.
*
* \return metadata dictionary
*/
- (NSDictionary*)getMetadataEntries;
/**
* Adds new stream.
*
* \param new stream information
*/
- (void)addStream:(StreamInformation*) stream;
/**
* Returns all streams
*
* \return streams array
*/
- (NSArray*)getStreams;
@end
+146
View File
@@ -0,0 +1,146 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg 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 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MediaInformation.h"
@implementation MediaInformation {
/**
* Format
*/
NSString *format;
/**
* Path
*/
NSString *path;
/**
* Duration, in milliseconds
*/
NSNumber *duration;
/**
* Start time, in milliseconds
*/
NSNumber *startTime;
/**
* Bitrate, kb/s
*/
NSNumber *bitrate;
/**
* Metadata map
*/
NSMutableDictionary *metadata;
/**
* List of streams
*/
NSMutableArray *streams;
/**
* Raw unparsed media information
*/
NSString *rawInformation;
}
- (instancetype)init {
self = [super init];
if (self) {
format = nil;
path = nil;
duration = nil;
startTime = nil;
bitrate = nil;
metadata = [[NSMutableDictionary alloc] init];
streams = [[NSMutableArray alloc] init];
rawInformation = nil;
}
return self;
}
- (NSString*)getFormat {
return format;
}
- (void)setFormat:(NSString*)newFormat {
format = newFormat;
}
- (NSString*)getPath {
return path;
}
- (void)setPath:(NSString*)newPath {
path = newPath;
}
- (NSNumber*)getDuration {
return duration;
}
- (void)setDuration:(NSNumber*)newDuration {
duration = newDuration;
}
- (NSNumber*)getStartTime {
return startTime;
}
- (void)setStartTime:(NSNumber*)newStartTime {
startTime = newStartTime;
}
- (NSNumber*)getBitrate {
return bitrate;
}
- (void)setBitrate:(NSNumber*)newBitrate {
bitrate = newBitrate;
}
- (NSString*)getRawInformation {
return rawInformation;
}
- (void)setRawInformation:(NSString*)newRawInformation {
rawInformation = newRawInformation;
}
- (void)addMetadata:(NSString*)key :(NSString*)value {
metadata[key] = value;
}
- (NSDictionary*)getMetadataEntries {
return metadata;
}
- (void)addStream:(StreamInformation*)stream {
[streams addObject:stream];
}
- (NSArray*)getStreams {
return streams;
}
@end
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg 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 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Foundation/Foundation.h>
#include "MediaInformation.h"
@interface MediaInformationParser : NSObject
/**
* Extracts MediaInformation from given command output.
*/
+ (MediaInformation*)from: (NSString*)rawCommandOutput;
/**
* Extracts StreamInformation from given input.
*/
+ (StreamInformation*)parseStreamBlock:(NSString*)input;
+ (void (^)(NSString *__autoreleasing*, NSString *__autoreleasing*))parseInputBlock:(NSString*)input;
+ (void (^)(NSNumber *__autoreleasing*, NSNumber *__autoreleasing*, NSNumber *__autoreleasing*))parseDurationBlock:(NSString*)input;
+ (void (^)(NSString *__autoreleasing*, NSString *__autoreleasing*))parseMetadataBlock:(NSString*)input;
+ (void (^)(NSNumber *__autoreleasing*, NSNumber *__autoreleasing*))parseVideoDimensions: (NSString*)input;
+ (NSString*)parseVideoStreamSampleAspectRatio: (NSString*)input;
+ (NSString*)parseVideoStreamDisplayAspectRatio: (NSString*)input;
+ (NSNumber*)parseAudioStreamSampleRate: (NSString*)input;
+ (NSString*)parseStreamType: (NSString*)input;
+ (NSString*)parseStreamCodec: (NSString*)input;
+ (NSString*)parseStreamFullCodec: (NSString*)input;
+ (NSNumber*)parseStreamIndex: (NSString*)input;
+ (NSNumber*)parseDuration: (NSString*)input;
+ (NSNumber*)parseStartTime: (NSString*)input;
+ (NSString*)substring:(NSString*)string from:(NSString*)start to:(NSString*)end ignoring:(NSArray*)ignoredTokens;
+ (NSString*)substring:(NSString*)string from:(NSString*)start ignoring:(NSArray*)ignoredTokens;
+ (NSString*)substring:(NSString*)string to:(NSString*)start ignoring:(NSArray*)ignoredTokens;
+ (int)index:(NSString*)string of:(NSString*)substring from:(int)startIndex times:(int)n;
+ (int)count:(NSString*)string of:(NSString*)substring;
+ (NSNumber*)toInteger: (NSString*)input;
+ (NSNumber*)toIntegerObject: (NSString*)input;
+ (NSString*)safeGet:(NSArray*)array from:(int)index;
@end
+590
View File
@@ -0,0 +1,590 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg 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 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MediaInformationParser.h"
static NSDateFormatter* durationFormat;
static NSDate* referenceDuration;
static NSRegularExpression *parenthesesRegex;
static NSRegularExpression *bracketsRegex;
@implementation MediaInformationParser
+ (void)initialize {
NSError *localError = nil;
durationFormat = [[NSDateFormatter alloc] init];
[durationFormat setDateFormat:@"HH:mm:ss"];
referenceDuration = [durationFormat dateFromString: @"00:00:00"];
parenthesesRegex = [NSRegularExpression regularExpressionWithPattern:@"\\(.*\\)" options:NSRegularExpressionCaseInsensitive error:&localError];
bracketsRegex = [NSRegularExpression regularExpressionWithPattern:@"\\[.*\\]" options:NSRegularExpressionCaseInsensitive error:&localError];
}
+ (MediaInformation*)from: (NSString*)rawCommandOutput {
MediaInformation* mediaInformation = [[MediaInformation alloc] init];
if (rawCommandOutput != nil) {
NSArray* split = [rawCommandOutput componentsSeparatedByString:@"\n"];
Boolean metadata = false;
StreamInformation *lastCreatedStream = nil;
NSMutableString *rawInformation = [[NSMutableString alloc] init];
for (int i=0; i < [split count]; i++) {
NSString *outputLine = [split objectAtIndex:i];
if ([outputLine hasPrefix:@"["]) {
metadata = false;
continue;
}
NSString *trimmedLine = [outputLine stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([trimmedLine hasPrefix:@"Input"]) {
metadata = false;
lastCreatedStream = nil;
void(^blockPair)(NSString **, NSString **) = [MediaInformationParser parseInputBlock:trimmedLine];
NSString *format;
NSString *path;
blockPair(&format, &path);
[mediaInformation setFormat:format];
[mediaInformation setPath:path];
} else if ([trimmedLine hasPrefix:@"Duration"]) {
metadata = false;
lastCreatedStream = nil;
void(^blockTrio)(NSNumber **, NSNumber **, NSNumber **) = [MediaInformationParser parseDurationBlock:trimmedLine];
NSNumber *duration;
NSNumber *startTime;
NSNumber *bitrate;
blockTrio(&duration, &startTime, &bitrate);
[mediaInformation setDuration:duration];
[mediaInformation setStartTime:startTime];
[mediaInformation setBitrate:bitrate];
} else if ([trimmedLine hasPrefix:@"Metadata"]) {
metadata = true;
} else if ([trimmedLine hasPrefix:@"Stream mapping"] || [trimmedLine hasPrefix:@"Press [q] to stop"] || [trimmedLine hasPrefix:@"Output"]) {
break;
} else if ([trimmedLine hasPrefix:@"Stream"]) {
metadata = false;
lastCreatedStream = [MediaInformationParser parseStreamBlock:trimmedLine];
[mediaInformation addStream:lastCreatedStream];
} else if (metadata) {
void(^blockPair)(NSString **, NSString **) = [MediaInformationParser parseMetadataBlock:trimmedLine];
NSString *key;
NSString *value;
blockPair(&key, &value);
if (key != nil && value != nil) {
if (lastCreatedStream != nil) {
[lastCreatedStream addMetadata:key:value];
} else {
[mediaInformation addMetadata:key:value];
}
}
}
[rawInformation appendString:outputLine];
[rawInformation appendString:@"\n"];
}
[mediaInformation setRawInformation:rawInformation];
}
return mediaInformation;
}
+ (void (^)(NSString *__autoreleasing*, NSString *__autoreleasing*))parseInputBlock:(NSString*)input {
NSString *format = [MediaInformationParser substring:input from:@"," to:@", from" ignoring:nil];
NSString *path = [MediaInformationParser substring:input from:@"'" to:@"'" ignoring:nil];
return ^(NSString **s1, NSString **s2){
*s1 = format;
*s2 = path;
};
}
+ (void (^)(NSNumber *__autoreleasing*, NSNumber *__autoreleasing*, NSNumber *__autoreleasing*))parseDurationBlock:(NSString*)input {
NSNumber *duration = [MediaInformationParser parseDuration:[MediaInformationParser substring:input from:@"Duration:" to:@"," ignoring:[[NSMutableArray alloc] initWithObjects:@"uration:", nil]]];
NSNumber *start = [MediaInformationParser parseStartTime:[MediaInformationParser substring:input from:@"start:" to:@"," ignoring:[[NSMutableArray alloc] initWithObjects:@"tart:", nil]]];
NSString *bitrateString = [MediaInformationParser substring:input from:@"bitrate:" ignoring:[[NSMutableArray alloc] initWithObjects:@"itrate:", @"kb/s", nil]];
NSNumber *bitrate = nil;
if (bitrateString != nil && ![bitrateString isEqualToString:@"N/A"]) {
bitrate = [MediaInformationParser toIntegerObject:bitrateString];
}
return ^(NSNumber **n1, NSNumber **n2, NSNumber **n3){
*n1 = duration;
*n2 = start;
*n3 = bitrate;
};
}
+ (void (^)(NSString *__autoreleasing*, NSString *__autoreleasing*))parseMetadataBlock:(NSString*)input {
NSString *key = nil;
NSString *value = nil;
if (input != nil) {
key = [MediaInformationParser substring:input to:@":" ignoring:[[NSMutableArray alloc] init]];
value = [MediaInformationParser substring:input from:@":" ignoring:[[NSMutableArray alloc] init]];
}
return ^(NSString **s1, NSString **s2){
*s1 = key;
*s2 = value;
};
}
+ (StreamInformation*)parseStreamBlock:(NSString*)input {
StreamInformation* streamInformation = [[StreamInformation alloc] init];
if (input != nil) {
[streamInformation setIndex:[MediaInformationParser parseStreamIndex:input]];
int typeBlockStartIndex = [MediaInformationParser index:input of:@":" from:0 times:2];
if ((typeBlockStartIndex > -1) && (typeBlockStartIndex < [input length])) {
NSString *streamBlock = [input substringFromIndex:(typeBlockStartIndex + 1)];
NSArray* parts = [streamBlock componentsSeparatedByString:@","];
NSString *typePart = [MediaInformationParser safeGet:parts from:0];
NSString *type = [MediaInformationParser parseStreamType:typePart];
[streamInformation setType:type];
[streamInformation setCodec:[MediaInformationParser parseStreamCodec:typePart]];
[streamInformation setFullCodec:[MediaInformationParser parseStreamFullCodec:typePart]];
NSString *part2 = [MediaInformationParser safeGet:parts from:1];
NSString *part3 = [MediaInformationParser safeGet:parts from:2];
NSString *part4 = [MediaInformationParser safeGet:parts from:3];
NSString *part5 = [MediaInformationParser safeGet:parts from:4];
if ([@"video" isEqualToString:type]) {
int lastUsedPart = 1;
if (part2 != nil) {
int pStart = [MediaInformationParser count:part2 of:@"("];
int pEnd = [MediaInformationParser count:part2 of:@")"];
while (pStart != pEnd) {
lastUsedPart++;
NSString *newPart = [MediaInformationParser safeGet:parts from:lastUsedPart];
if (newPart == nil) {
break;
}
part2 = [NSString stringWithFormat:@"%@,%@", part2, newPart];
pStart = [MediaInformationParser count:part2 of:@"("];
pEnd = [MediaInformationParser count:part2 of:@")"];
}
part2 = [part2 lowercaseString];
part2 = [part2 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setFullFormat:part2];
NSString *formattedPart2 = [parenthesesRegex stringByReplacingMatchesInString:part2 options:0 range:NSMakeRange(0, [part2 length]) withTemplate:@""];
formattedPart2 = [formattedPart2 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setFormat:formattedPart2];
}
lastUsedPart++;
NSString *videoDimensionPart = [MediaInformationParser safeGet:parts from:lastUsedPart];
if (videoDimensionPart != nil) {
NSString *videoLayout = [videoDimensionPart lowercaseString];
videoLayout = [videoLayout stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
void(^dimensions)(NSNumber **, NSNumber **) = [MediaInformationParser parseVideoDimensions:videoLayout];
NSNumber *width;
NSNumber *height;
dimensions(&width, &height);
[streamInformation setWidth:width];
[streamInformation setHeight:height];
[streamInformation setSampleAspectRatio:[MediaInformationParser parseVideoStreamSampleAspectRatio:videoLayout]];
[streamInformation setDisplayAspectRatio:[MediaInformationParser parseVideoStreamDisplayAspectRatio:videoLayout]];
}
for (int i = lastUsedPart + 1; i < [parts count]; i++) {
NSString *part = [parts objectAtIndex:i];
part = [parenthesesRegex stringByReplacingMatchesInString:part options:0 range:NSMakeRange(0, [part length]) withTemplate:@""];
part = [part lowercaseString];
if ([part rangeOfString:@"kb/s"].location != NSNotFound) {
part = [part stringByReplacingOccurrencesOfString:@"kb/s" withString:@""];
part = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSNumber *bitrate = [MediaInformationParser toIntegerObject:part];
[streamInformation setBitrate:bitrate];
} else if ([part rangeOfString:@"fps"].location != NSNotFound) {
part = [part stringByReplacingOccurrencesOfString:@"fps" withString:@""];
part = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setAverageFrameRate:part];
} else if ([part rangeOfString:@"tbr"].location != NSNotFound) {
part = [part stringByReplacingOccurrencesOfString:@"tbr" withString:@""];
part = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setRealFrameRate:part];
} else if ([part rangeOfString:@"tbn"].location != NSNotFound) {
part = [part stringByReplacingOccurrencesOfString:@"tbn" withString:@""];
part = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setTimeBase:part];
} else if ([part rangeOfString:@"tbc"].location != NSNotFound) {
part = [part stringByReplacingOccurrencesOfString:@"tbc" withString:@""];
part = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setCodecTimeBase:part];
}
}
}
if ([@"audio" isEqualToString:type]) {
if (part2 != nil) {
[streamInformation setSampleRate:[MediaInformationParser parseAudioStreamSampleRate:part2]];
}
if (part3 != nil) {
NSString *formattedPart3 = [part3 lowercaseString];
formattedPart3 = [formattedPart3 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setChannelLayout:formattedPart3];
}
if (part4 != nil) {
NSString *formattedPart4 = [part4 lowercaseString];
formattedPart4 = [formattedPart4 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setSampleFormat:formattedPart4];
}
if (part5 != nil) {
NSString *formattedPart5 = [part5 lowercaseString];
formattedPart5 = [parenthesesRegex stringByReplacingMatchesInString:formattedPart5 options:0 range:NSMakeRange(0, [formattedPart5 length]) withTemplate:@""];
formattedPart5 = [formattedPart5 stringByReplacingOccurrencesOfString:@"kb/s" withString:@""];
formattedPart5 = [formattedPart5 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[streamInformation setBitrate:[MediaInformationParser toIntegerObject:formattedPart5]];
}
}
}
}
return streamInformation;
}
+ (void (^)(NSNumber *__autoreleasing*, NSNumber *__autoreleasing*))parseVideoDimensions: (NSString*)input {
NSNumber *width = nil;
NSNumber *height = nil;
if (input != nil) {
NSString *formattedString = [input lowercaseString];
formattedString = [bracketsRegex stringByReplacingMatchesInString:formattedString options:0 range:NSMakeRange(0, [formattedString length]) withTemplate:@""];
NSString *widthString = [MediaInformationParser substring:formattedString to:@"x" ignoring:[[NSMutableArray alloc] init]];
NSString *heightString = [MediaInformationParser substring:formattedString from:@"x" ignoring:[[NSMutableArray alloc] init]];
width = [MediaInformationParser toIntegerObject:widthString];
height = [MediaInformationParser toIntegerObject:heightString];
}
return ^(NSNumber **n1, NSNumber **n2){
*n1 = width;
*n2 = height;
};
}
+ (NSString*)parseVideoStreamSampleAspectRatio: (NSString*)input {
if (input != nil) {
NSString *formattedString = [input lowercaseString];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"[" withString:@""];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"]" withString:@""];
NSArray* parts = [formattedString componentsSeparatedByString:@" "];
for (int i=0; i < [parts count]; i++) {
NSString *token = [parts objectAtIndex:i];
if ([token isEqualToString:@"sar"]) {
return [MediaInformationParser safeGet:parts from:(i + 1)];
}
}
}
return nil;
}
+ (NSString*)parseVideoStreamDisplayAspectRatio: (NSString*)input {
if (input != nil) {
NSString *formattedString = [input lowercaseString];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"[" withString:@""];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"]" withString:@""];
NSArray* parts = [formattedString componentsSeparatedByString:@" "];
for (int i=0; i < [parts count]; i++) {
NSString *token = [parts objectAtIndex:i];
if ([token isEqualToString:@"dar"]) {
return [MediaInformationParser safeGet:parts from:(i + 1)];
}
}
}
return nil;
}
+ (NSNumber*)parseAudioStreamSampleRate: (NSString*)input {
if (input != nil) {
Boolean khz = false;
Boolean mhz = false;
NSString *lowerCaseString = [input lowercaseString];
if ([lowerCaseString rangeOfString:@"khz"].location != NSNotFound) {
khz = true;
}
if ([lowerCaseString rangeOfString:@"mhz"].location != NSNotFound) {
mhz = true;
}
lowerCaseString = [lowerCaseString stringByReplacingOccurrencesOfString:@"khz" withString:@""];
lowerCaseString = [lowerCaseString stringByReplacingOccurrencesOfString:@"mhz" withString:@""];
lowerCaseString = [lowerCaseString stringByReplacingOccurrencesOfString:@"hz" withString:@""];
NSNumber *sampleRate = [MediaInformationParser toInteger:[lowerCaseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
if (khz) {
return [NSNumber numberWithInteger:(1000*sampleRate.intValue)];
} else if (mhz) {
return [NSNumber numberWithInteger:(1000000*sampleRate.intValue)];
} else {
return sampleRate;
}
}
return nil;
}
+ (NSString*)parseStreamType: (NSString*)input {
if (input != nil) {
NSString *formattedString = [input lowercaseString];
if ([formattedString rangeOfString:@"audio:"].location != NSNotFound) {
return @"audio";
} else if ([formattedString rangeOfString:@"video:"].location != NSNotFound) {
return @"video";
}
}
return nil;
}
+ (NSString*)parseStreamCodec: (NSString*)input {
if (input != nil) {
NSString *formattedString = [input lowercaseString];
formattedString = [parenthesesRegex stringByReplacingMatchesInString:formattedString options:0 range:NSMakeRange(0, [formattedString length]) withTemplate:@""];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"video:" withString:@""];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"audio:" withString:@""];
return [formattedString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
return nil;
}
+ (NSString*)parseStreamFullCodec: (NSString*)input {
if (input != nil) {
NSString *formattedString = [input lowercaseString];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"video:" withString:@""];
formattedString = [formattedString stringByReplacingOccurrencesOfString:@"audio:" withString:@""];
return [formattedString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
return nil;
}
+ (NSNumber*)parseStreamIndex: (NSString*)input {
NSString *substring = [MediaInformationParser substring:input from:@"Stream #0:" to:@":" ignoring:[[NSMutableArray alloc] initWithObjects:@"tream #0", nil]];
if (substring != nil) {
substring = [substring stringByReplacingOccurrencesOfString:@":" withString:@""];
substring = [parenthesesRegex stringByReplacingMatchesInString:substring options:0 range:NSMakeRange(0, [substring length]) withTemplate:@""];
return [MediaInformationParser toIntegerObject:substring];
}
return nil;
}
+ (NSNumber*)parseDuration: (NSString*)input {
if (input != nil && ![input isEqualToString:@"N/A"]) {
NSString *seconds = [MediaInformationParser substring:input to:@"." ignoring:[[NSMutableArray alloc] init]];
if (seconds != nil) {
NSDate* durationDate = [durationFormat dateFromString: seconds];
if (durationDate != nil) {
NSTimeInterval secondsInMilliseconds = [durationDate timeIntervalSinceDate:referenceDuration]*1000;
NSNumber *centiSeconds = [MediaInformationParser toInteger:[MediaInformationParser substring:input from:@"." ignoring:[[NSMutableArray alloc] init]]];
secondsInMilliseconds += centiSeconds.intValue*10;
return [NSNumber numberWithInteger:secondsInMilliseconds];
}
}
}
return nil;
}
+ (NSNumber*)parseStartTime: (NSString*)input {
if (input != nil && ![input isEqualToString:@"N/A"] && ([input length]>0)) {
double inputAsDouble = [input doubleValue];
return [NSNumber numberWithInteger:ceil(inputAsDouble*1000)];
}
return nil;
}
+ (NSString*)substring:(NSString*)string from:(NSString*)start to:(NSString*)end ignoring:(NSArray*)ignoredTokens {
NSString *extractedSubstring = nil;
if (string != nil) {
NSRange formatStart = [string rangeOfString:start];
if (formatStart.location != NSNotFound && (formatStart.location + start.length < [string length])) {
NSRange formatEnd = [string rangeOfString:end options:NSLiteralSearch range:NSMakeRange(formatStart.location + start.length, string.length - (formatStart.location + start.length + 1))];
if (formatEnd.location != NSNotFound) {
extractedSubstring = [string substringWithRange:NSMakeRange(formatStart.location + start.length, formatEnd.location - (formatStart.location + start.length))];
}
}
}
if ((ignoredTokens != nil) && (extractedSubstring != nil)) {
for (int i=0; i < [ignoredTokens count]; i++) {
NSString *token = [ignoredTokens objectAtIndex:i];
extractedSubstring = [extractedSubstring stringByReplacingOccurrencesOfString:token withString:@""];
}
}
return (extractedSubstring == nil) ? nil : [extractedSubstring stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
+ (NSString*)substring:(NSString*)string from:(NSString*)start ignoring:(NSArray*)ignoredTokens {
NSString *extractedSubstring = nil;
if (string != nil) {
NSRange formatStart = [string rangeOfString:start];
if (formatStart.location != NSNotFound) {
extractedSubstring = [string substringWithRange:NSMakeRange(formatStart.location + start.length, string.length - (formatStart.location + start.length))];
}
}
if ((ignoredTokens != nil) && (extractedSubstring != nil)) {
for (int i=0; i < [ignoredTokens count]; i++) {
NSString *token = [ignoredTokens objectAtIndex:i];
extractedSubstring = [extractedSubstring stringByReplacingOccurrencesOfString:token withString:@""];
}
}
return (extractedSubstring == nil) ? nil : [extractedSubstring stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
+ (NSString*)substring:(NSString*)string to:(NSString*)start ignoring:(NSArray*)ignoredTokens {
NSString *extractedSubstring = nil;
if (string != nil) {
NSRange formatStart = [string rangeOfString:start];
if (formatStart.location != NSNotFound) {
extractedSubstring = [string substringWithRange:NSMakeRange(0, formatStart.location)];
}
}
if ((ignoredTokens != nil) && (extractedSubstring != nil)) {
for (int i=0; i < [ignoredTokens count]; i++) {
NSString *token = [ignoredTokens objectAtIndex:i];
extractedSubstring = [extractedSubstring stringByReplacingOccurrencesOfString:token withString:@""];
}
}
return (extractedSubstring == nil) ? nil : [extractedSubstring stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
+ (int)index:(NSString*)string of:(NSString*)substring from:(int)startIndex times:(int)n {
int count = 1;
startIndex -= substring.length;
while (count <= n) {
unsigned long searchIndex = startIndex + (int)substring.length;
NSRange currentRange = [string rangeOfString:substring options:NSLiteralSearch range:NSMakeRange(searchIndex, string.length - searchIndex)];
if (currentRange.location != NSNotFound) {
startIndex = (int)currentRange.location;
}
count++;
}
return startIndex;
}
+ (int)count:(NSString*)string of:(NSString*)substring {
int count = 0;
int index = 0 - (int)substring.length;
do {
int searchIndex = index + (int)substring.length;
NSRange currentRange = [string rangeOfString:substring options:NSLiteralSearch range:NSMakeRange(searchIndex, string.length - searchIndex)];
if (currentRange.location != NSNotFound) {
count++;
index = (int)currentRange.location;
} else {
index = -1;
}
} while (index >= 0);
return count;
}
+ (NSNumber*)toInteger: (NSString*)input {
if (input == nil) {
return [NSNumber numberWithInt:0];
}
return [NSNumber numberWithInteger:input.integerValue];
}
+ (NSNumber*)toIntegerObject: (NSString*)input {
if (input == nil) {
return nil;
}
return [NSNumber numberWithInteger:input.integerValue];
}
+ (NSString*)safeGet:(NSArray*)array from:(int)index {
if (array == nil) {
return nil;
}
unsigned long size = [array count];
if (size > index) {
return [array objectAtIndex:index];
} else {
return nil;
}
}
@end
+292
View File
@@ -0,0 +1,292 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg 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 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Foundation/Foundation.h>
@interface StreamInformation : NSObject
- (instancetype)init;
/**
* Returns stream index.
*
* \return stream index, starting from zero
*/
- (NSNumber*)getIndex;
/**
* Sets stream index.
*
* \param stream index, starting from zero
*/
- (void)setIndex:(NSNumber*) index;
/**
* Returns stream type.
*
* \return stream type; audio or video
*/
- (NSString*)getType;
/**
* Sets stream type.
*
* \param stream type; audio or video
*/
- (void)setType:(NSString*) type;
/**
* Returns stream codec.
*
* \return stream codec
*/
- (NSString*)getCodec;
/**
* Sets stream codec.
*
* \param stream codec
*/
- (void)setCodec:(NSString*) codec;
/**
* Returns full stream codec.
*
* \return stream codec with additional profile and mode information
*/
- (NSString*)getFullCodec;
/**
* Sets full stream codec.
*
* \param stream codec with additional profile and mode information
*/
- (void)setFullCodec:(NSString*) fullCodec;
/**
* Returns stream format.
*
* \return stream format
*/
- (NSString*)getFormat;
/**
* Sets stream format.
*
* \param stream format
*/
- (void)setFormat:(NSString*) format;
/**
* Returns full stream format.
*
* \return stream format with
*/
- (NSString*)getFullFormat;
/**
* Sets full stream format.
*
* \param stream format with
*/
- (void)setFullFormat:(NSString*) fullFormat;
/**
* Returns width.
*
* \return width in pixels
*/
- (NSNumber*)getWidth;
/**
* Sets width.
*
* \param width in pixels
*/
- (void)setWidth:(NSNumber*) width;
/**
* Returns height.
*
* \return height in pixels
*/
- (NSNumber*)getHeight;
/**
* Sets height.
*
* \param height in pixels
*/
- (void)setHeight:(NSNumber*) height;
/**
* Returns bitrate.
*
* \return bitrate in kb/s
*/
- (NSNumber*)getBitrate;
/**
* Sets bitrate.
*
* \param bitrate in kb/s
*/
- (void)setBitrate:(NSNumber*) bitrate;
/**
* Returns sample rate.
*
* \return sample rate in hz
*/
- (NSNumber*)getSampleRate;
/**
* Sets sample rate.
*
* \param sample rate in hz
*/
- (void)setSampleRate:(NSNumber*) sampleRate;
/**
* Returns sample format.
*
* \return sample format
*/
- (NSString*)getSampleFormat;
/**
* Sets sample format.
*
* \param sample format
*/
- (void)setSampleFormat:(NSString*) sampleFormat;
/**
* Returns channel layout.
*
* \return channel layout
*/
- (NSString*)getChannelLayout;
/**
* Sets channel layout.
*
* \param channel layout
*/
- (void)setChannelLayout:(NSString*) channelLayout;
/**
* Returns sample aspect ratio.
*
* \return sample aspect ratio
*/
- (NSString*)getSampleAspectRatio;
/**
* Sets sample aspect ratio.
*
* \param sample aspect ratio
*/
- (void)setSampleAspectRatio:(NSString*) sampleAspectRatio;
/**
* Returns display aspect ratio.
*
* \return display aspect ratio
*/
- (NSString*)getDisplayAspectRatio;
/**
* Sets display aspect ratio.
*
* \param display aspect ratio
*/
- (void)setDisplayAspectRatio:(NSString*) displayAspectRatio;
/**
* Returns average frame rate.
*
* \return average frame rate in fps
*/
- (NSString*)getAverageFrameRate;
/**
* Sets average frame rate.
*
* \param average frame rate in fps
*/
- (void)setAverageFrameRate:(NSString*) averageFrameRatehn;
/**
* Returns real frame rate.
*
* \return real frame rate in tbr
*/
- (NSString*)getRealFrameRate;
/**
* Sets real frame rate.
*
* \param real frame rate in tbr
*/
- (void)setRealFrameRate:(NSString*) realFrameRate;
/**
* Returns time base.
*
* \return time base in tbn
*/
- (NSString*)getTimeBase;
/**
* Sets time base.
*
* \param time base in tbn
*/
- (void)setTimeBase:(NSString*) timeBase;
/**
* Returns codec time base.
*
* \return codec time base in tbc
*/
- (NSString*)getCodecTimeBase;
/**
* Sets codec time base.
*
* \param codec time base in tbc
*/
- (void)setCodecTimeBase:(NSString*) codecTimeBase;
/**
* Adds metadata.
*
* \param metadata key and value
*/
- (void)addMetadata:(NSString*)key :(NSString*)value;
/**
* Returns all metadata entries.
*
* \return metadata dictionary
*/
- (NSDictionary*)getMetadataEntries;
@end
+259
View File
@@ -0,0 +1,259 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg 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 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include "StreamInformation.h"
@implementation StreamInformation {
/**
* Stream index
*/
NSNumber *index;
NSString *type;
NSString *codec;
NSString *fullCodec;
NSString *format;
NSString *fullFormat;
NSNumber *width;
NSNumber *height;
NSNumber *bitrate;
NSNumber *sampleRate;
NSString *sampleFormat;
NSString *channelLayout;
/**
* SAR
*/
NSString *sampleAspectRatio;
/**
* DAR
*/
NSString *displayAspectRatio;
/**
* fps
*/
NSString *averageFrameRate;
/**
* tbr
*/
NSString *realFrameRate;
/**
* tbn
*/
NSString *timeBase;
/**
* tbc
*/
NSString *codecTimeBase;
/**
* Metadata map
*/
NSMutableDictionary *metadata;
}
- (instancetype)init {
self = [super init];
if (self) {
index = nil;
type = nil;
codec = nil;
fullCodec = nil;
format = nil;
fullFormat = nil;
width = nil;
height = nil;
bitrate = nil;
sampleRate = nil;
sampleFormat = nil;
channelLayout = nil;
sampleAspectRatio = nil;
displayAspectRatio = nil;
averageFrameRate = nil;
realFrameRate = nil;
timeBase = nil;
codecTimeBase = nil;
metadata = nil;
}
return self;
}
- (NSNumber*)getIndex {
return index;
}
- (void)setIndex:(NSNumber*) newIndex {
index = newIndex;
}
- (NSString*)getType {
return type;
}
- (void)setType:(NSString*) newType {
type = newType;
}
- (NSString*)getCodec {
return codec;
}
- (void)setCodec:(NSString*) newCodec {
codec = newCodec;
}
- (NSString*)getFullCodec {
return fullCodec;
}
- (void)setFullCodec:(NSString*) newFullCodec {
fullCodec = newFullCodec;
}
- (NSString*)getFormat {
return format;
}
- (void)setFormat:(NSString*) newFormat {
format = newFormat;
}
- (NSString*)getFullFormat {
return fullFormat;
}
- (void)setFullFormat:(NSString*) newFullFormat {
fullFormat = newFullFormat;
}
- (NSNumber*)getWidth {
return width;
}
- (void)setWidth:(NSNumber*) newWidth {
width = newWidth;
}
- (NSNumber*)getHeight {
return height;
}
- (void)setHeight:(NSNumber*) newHeight {
height = newHeight;
}
- (NSNumber*)getBitrate {
return bitrate;
}
- (void)setBitrate:(NSNumber*) newBitrate {
bitrate = newBitrate;
}
- (NSNumber*)getSampleRate {
return sampleRate;
}
- (void)setSampleRate:(NSNumber*) newSampleRate {
sampleRate = newSampleRate;
}
- (NSString*)getSampleFormat {
return sampleFormat;
}
- (void)setSampleFormat:(NSString*) newSampleFormat {
sampleFormat = newSampleFormat;
}
- (NSString*)getChannelLayout {
return channelLayout;
}
- (void)setChannelLayout:(NSString*) newChannelLayout {
channelLayout = newChannelLayout;
}
- (NSString*)getSampleAspectRatio {
return sampleAspectRatio;
}
- (void)setSampleAspectRatio:(NSString*) newSampleAspectRatio {
sampleAspectRatio = newSampleAspectRatio;
}
- (NSString*)getDisplayAspectRatio {
return displayAspectRatio;
}
- (void)setDisplayAspectRatio:(NSString*) newDisplayAspectRatio {
displayAspectRatio = newDisplayAspectRatio;
}
- (NSString*)getAverageFrameRate {
return averageFrameRate;
}
- (void)setAverageFrameRate:(NSString*) newAverageFrameRatehn {
averageFrameRate = newAverageFrameRatehn;
}
- (NSString*)getRealFrameRate {
return realFrameRate;
}
- (void)setRealFrameRate:(NSString*) newRealFrameRate {
realFrameRate = newRealFrameRate;
}
- (NSString*)getTimeBase {
return timeBase;
}
- (void)setTimeBase:(NSString*) newTimeBase {
timeBase = newTimeBase;
}
- (NSString*)getCodecTimeBase {
return codecTimeBase;
}
- (void)setCodecTimeBase:(NSString*) newCodecTimeBase {
codecTimeBase = newCodecTimeBase;
}
- (void)addMetadata:(NSString*)key :(NSString*)value {
metadata[key] = value;
}
- (NSDictionary*)getMetadataEntries {
return metadata;
}
@end
@@ -9,6 +9,8 @@
/* Begin PBXBuildFile section */
340FABBE2115A17600B33CE7 /* VidStabViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 340FABBC2115A17600B33CE7 /* VidStabViewController.h */; };
340FABBF2115A17600B33CE7 /* VidStabViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FABBD2115A17600B33CE7 /* VidStabViewController.m */; };
3423D267217F7CC100C3C7ED /* MediaInformationParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3423D266217F7CC100C3C7ED /* MediaInformationParserTests.m */; };
3423D269217F7D4E00C3C7ED /* MediaInformationParserTests.h in Headers */ = {isa = PBXBuildFile; fileRef = 3423D268217F7D4E00C3C7ED /* MediaInformationParserTests.h */; };
343E66B5210784BD00F95E5B /* HttpsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 343E66B3210784BD00F95E5B /* HttpsViewController.h */; };
343E66B6210784BD00F95E5B /* HttpsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 343E66B4210784BD00F95E5B /* HttpsViewController.m */; };
343E66B9210789DE00F95E5B /* Constants.h in Headers */ = {isa = PBXBuildFile; fileRef = 343E66B7210789DE00F95E5B /* Constants.h */; };
@@ -24,6 +26,22 @@
348439EE20B2EFAF001A3990 /* tajmahal.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 348439EB20B2EFAF001A3990 /* tajmahal.jpg */; };
348439EF20B2EFAF001A3990 /* colosseum.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 348439EC20B2EFAF001A3990 /* colosseum.jpg */; };
34BB547C2109D44800606B7C /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 34BB547B2109D44800606B7C /* Constants.m */; };
34C5E89E217F7F86001DCD99 /* libavfilter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E896217F7F86001DCD99 /* libavfilter.framework */; };
34C5E89F217F7F86001DCD99 /* libavcodec.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E897217F7F86001DCD99 /* libavcodec.framework */; };
34C5E8A0217F7F86001DCD99 /* libswresample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E898217F7F86001DCD99 /* libswresample.framework */; };
34C5E8A1217F7F86001DCD99 /* libavutil.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E899217F7F86001DCD99 /* libavutil.framework */; };
34C5E8A2217F7F86001DCD99 /* libswscale.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89A217F7F86001DCD99 /* libswscale.framework */; };
34C5E8A3217F7F86001DCD99 /* libavformat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89B217F7F86001DCD99 /* libavformat.framework */; };
34C5E8A4217F7F86001DCD99 /* mobileffmpeg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89C217F7F86001DCD99 /* mobileffmpeg.framework */; };
34C5E8A5217F7F86001DCD99 /* libavdevice.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89D217F7F86001DCD99 /* libavdevice.framework */; };
34C5E8A6217F7F92001DCD99 /* libavcodec.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E897217F7F86001DCD99 /* libavcodec.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34C5E8A7217F7F92001DCD99 /* libavdevice.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89D217F7F86001DCD99 /* libavdevice.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34C5E8A8217F7F92001DCD99 /* libavfilter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E896217F7F86001DCD99 /* libavfilter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34C5E8A9217F7F92001DCD99 /* libavformat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89B217F7F86001DCD99 /* libavformat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34C5E8AA217F7F92001DCD99 /* libavutil.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E899217F7F86001DCD99 /* libavutil.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34C5E8AB217F7F92001DCD99 /* libswresample.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E898217F7F86001DCD99 /* libswresample.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34C5E8AC217F7F92001DCD99 /* libswscale.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89A217F7F86001DCD99 /* libswscale.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34C5E8AD217F7F92001DCD99 /* mobileffmpeg.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34C5E89C217F7F86001DCD99 /* mobileffmpeg.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34DC789B21215B5800C3486C /* truenorg.otf in Resources */ = {isa = PBXBuildFile; fileRef = 34DC789721215B5800C3486C /* truenorg.otf */; };
34DC789C21215B5800C3486C /* subtitle.srt in Resources */ = {isa = PBXBuildFile; fileRef = 34DC789821215B5800C3486C /* subtitle.srt */; };
34DC789D21215B5800C3486C /* doppioone_regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34DC789921215B5800C3486C /* doppioone_regular.ttf */; };
@@ -45,6 +63,14 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
34C5E8A6217F7F92001DCD99 /* libavcodec.framework in Embed Frameworks */,
34C5E8A7217F7F92001DCD99 /* libavdevice.framework in Embed Frameworks */,
34C5E8A8217F7F92001DCD99 /* libavfilter.framework in Embed Frameworks */,
34C5E8A9217F7F92001DCD99 /* libavformat.framework in Embed Frameworks */,
34C5E8AA217F7F92001DCD99 /* libavutil.framework in Embed Frameworks */,
34C5E8AB217F7F92001DCD99 /* libswresample.framework in Embed Frameworks */,
34C5E8AC217F7F92001DCD99 /* libswscale.framework in Embed Frameworks */,
34C5E8AD217F7F92001DCD99 /* mobileffmpeg.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -55,6 +81,8 @@
09762EB4030C758C5727BD68 /* Pods-MobileFFmpegTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MobileFFmpegTest.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MobileFFmpegTest/Pods-MobileFFmpegTest.debug.xcconfig"; sourceTree = "<group>"; };
340FABBC2115A17600B33CE7 /* VidStabViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VidStabViewController.h; sourceTree = "<group>"; };
340FABBD2115A17600B33CE7 /* VidStabViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VidStabViewController.m; sourceTree = "<group>"; };
3423D266217F7CC100C3C7ED /* MediaInformationParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaInformationParserTests.m; sourceTree = "<group>"; };
3423D268217F7D4E00C3C7ED /* MediaInformationParserTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaInformationParserTests.h; sourceTree = "<group>"; };
343E66B3210784BD00F95E5B /* HttpsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HttpsViewController.h; sourceTree = "<group>"; };
343E66B4210784BD00F95E5B /* HttpsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HttpsViewController.m; sourceTree = "<group>"; };
343E66B7210789DE00F95E5B /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; };
@@ -70,6 +98,14 @@
348439EB20B2EFAF001A3990 /* tajmahal.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = tajmahal.jpg; sourceTree = "<group>"; };
348439EC20B2EFAF001A3990 /* colosseum.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = colosseum.jpg; sourceTree = "<group>"; };
34BB547B2109D44800606B7C /* Constants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Constants.m; sourceTree = "<group>"; };
34C5E896217F7F86001DCD99 /* libavfilter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libavfilter.framework; sourceTree = "<group>"; };
34C5E897217F7F86001DCD99 /* libavcodec.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libavcodec.framework; sourceTree = "<group>"; };
34C5E898217F7F86001DCD99 /* libswresample.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libswresample.framework; sourceTree = "<group>"; };
34C5E899217F7F86001DCD99 /* libavutil.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libavutil.framework; sourceTree = "<group>"; };
34C5E89A217F7F86001DCD99 /* libswscale.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libswscale.framework; sourceTree = "<group>"; };
34C5E89B217F7F86001DCD99 /* libavformat.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libavformat.framework; sourceTree = "<group>"; };
34C5E89C217F7F86001DCD99 /* mobileffmpeg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = mobileffmpeg.framework; sourceTree = "<group>"; };
34C5E89D217F7F86001DCD99 /* libavdevice.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libavdevice.framework; sourceTree = "<group>"; };
34DC789721215B5800C3486C /* truenorg.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = truenorg.otf; sourceTree = "<group>"; };
34DC789821215B5800C3486C /* subtitle.srt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = subtitle.srt; sourceTree = "<group>"; };
34DC789921215B5800C3486C /* doppioone_regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = doppioone_regular.ttf; sourceTree = "<group>"; };
@@ -95,7 +131,15 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
34C5E8A1217F7F86001DCD99 /* libavutil.framework in Frameworks */,
34C5E89F217F7F86001DCD99 /* libavcodec.framework in Frameworks */,
34C5E8A0217F7F86001DCD99 /* libswresample.framework in Frameworks */,
34C5E8A2217F7F86001DCD99 /* libswscale.framework in Frameworks */,
34C5E8A5217F7F86001DCD99 /* libavdevice.framework in Frameworks */,
8A776E4D8F4EB85888ADFB99 /* Pods_MobileFFmpegTest.framework in Frameworks */,
34C5E89E217F7F86001DCD99 /* libavfilter.framework in Frameworks */,
34C5E8A3217F7F86001DCD99 /* libavformat.framework in Frameworks */,
34C5E8A4217F7F86001DCD99 /* mobileffmpeg.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -119,6 +163,14 @@
3498DC65209F7F1C005F5883 /* Frameworks */ = {
isa = PBXGroup;
children = (
34C5E897217F7F86001DCD99 /* libavcodec.framework */,
34C5E89D217F7F86001DCD99 /* libavdevice.framework */,
34C5E896217F7F86001DCD99 /* libavfilter.framework */,
34C5E89B217F7F86001DCD99 /* libavformat.framework */,
34C5E899217F7F86001DCD99 /* libavutil.framework */,
34C5E898217F7F86001DCD99 /* libswresample.framework */,
34C5E89A217F7F86001DCD99 /* libswscale.framework */,
34C5E89C217F7F86001DCD99 /* mobileffmpeg.framework */,
F4B824D376F9CD476C761D40 /* Pods_MobileFFmpegTest.framework */,
);
name = Frameworks;
@@ -147,30 +199,32 @@
isa = PBXGroup;
children = (
34FAE213209F7DDD005CE2AE /* AppDelegate.h */,
345745492113B8AD00059043 /* AudioViewController.h */,
34FAE216209F7DDD005CE2AE /* CommandViewController.h */,
343E66B7210789DE00F95E5B /* Constants.h */,
343E66B3210784BD00F95E5B /* HttpsViewController.h */,
3457454D2113B8D300059043 /* SubtitleViewController.h */,
343E67072107C27600F95E5B /* TabBarController.h */,
343E67032107AD0100F95E5B /* Util.h */,
34FAE219209F7DDD005CE2AE /* VideoViewController.h */,
340FABBC2115A17600B33CE7 /* VidStabViewController.h */,
34FAE214209F7DDD005CE2AE /* AppDelegate.m */,
3457454A2113B8AD00059043 /* AudioViewController.m */,
34FAE217209F7DDD005CE2AE /* CommandViewController.m */,
34BB547B2109D44800606B7C /* Constants.m */,
343E66B4210784BD00F95E5B /* HttpsViewController.m */,
34FAE225209F7DDE005CE2AE /* main.m */,
3457454E2113B8D300059043 /* SubtitleViewController.m */,
343E67082107C27600F95E5B /* TabBarController.m */,
343E67042107AD0100F95E5B /* Util.m */,
34FAE21A209F7DDD005CE2AE /* VideoViewController.m */,
340FABBD2115A17600B33CE7 /* VidStabViewController.m */,
34FAE224209F7DDE005CE2AE /* Info.plist */,
34FAE21F209F7DDE005CE2AE /* Assets.xcassets */,
345745492113B8AD00059043 /* AudioViewController.h */,
3457454A2113B8AD00059043 /* AudioViewController.m */,
34FAE216209F7DDD005CE2AE /* CommandViewController.h */,
34FAE217209F7DDD005CE2AE /* CommandViewController.m */,
343E66B7210789DE00F95E5B /* Constants.h */,
34BB547B2109D44800606B7C /* Constants.m */,
343E66B3210784BD00F95E5B /* HttpsViewController.h */,
343E66B4210784BD00F95E5B /* HttpsViewController.m */,
34FAE224209F7DDE005CE2AE /* Info.plist */,
34FAE221209F7DDE005CE2AE /* LaunchScreen.storyboard */,
34FAE225209F7DDE005CE2AE /* main.m */,
34FAE21C209F7DDD005CE2AE /* Main.storyboard */,
3423D268217F7D4E00C3C7ED /* MediaInformationParserTests.h */,
3423D266217F7CC100C3C7ED /* MediaInformationParserTests.m */,
3457454D2113B8D300059043 /* SubtitleViewController.h */,
3457454E2113B8D300059043 /* SubtitleViewController.m */,
343E67072107C27600F95E5B /* TabBarController.h */,
343E67082107C27600F95E5B /* TabBarController.m */,
343E67032107AD0100F95E5B /* Util.h */,
343E67042107AD0100F95E5B /* Util.m */,
34FAE219209F7DDD005CE2AE /* VideoViewController.h */,
34FAE21A209F7DDD005CE2AE /* VideoViewController.m */,
340FABBC2115A17600B33CE7 /* VidStabViewController.h */,
340FABBD2115A17600B33CE7 /* VidStabViewController.m */,
);
path = MobileFFmpegTest;
sourceTree = "<group>";
@@ -192,6 +246,7 @@
buildActionMask = 2147483647;
files = (
343E67092107C27600F95E5B /* TabBarController.h in Headers */,
3423D269217F7D4E00C3C7ED /* MediaInformationParserTests.h in Headers */,
3457454B2113B8AD00059043 /* AudioViewController.h in Headers */,
3457454F2113B8D300059043 /* SubtitleViewController.h in Headers */,
343E66B9210789DE00F95E5B /* Constants.h in Headers */,
@@ -345,6 +400,7 @@
343E66B6210784BD00F95E5B /* HttpsViewController.m in Sources */,
340FABBF2115A17600B33CE7 /* VidStabViewController.m in Sources */,
34FAE218209F7DDD005CE2AE /* CommandViewController.m in Sources */,
3423D267217F7CC100C3C7ED /* MediaInformationParserTests.m in Sources */,
343E670A2107C27600F95E5B /* TabBarController.m in Sources */,
345745502113B8D300059043 /* SubtitleViewController.m in Sources */,
343E67062107AD0100F95E5B /* Util.m in Sources */,
@@ -0,0 +1,25 @@
//
// MediaInformationParserTests.h
//
// Copyright (c) 2018 Taner Sener
//
// This file is part of MobileFFmpeg.
//
// MobileFFmpeg 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 3 of the License, or
// (at your option) any later version.
//
// MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
//
/**
* All parsing tests are initiated from this method
*/
void runMediaInformationParserTests();
@@ -0,0 +1,841 @@
//
// MediaInformationParserTests.m
//
// Copyright (c) 2018 Taner Sener
//
// This file is part of MobileFFmpeg.
//
// MobileFFmpeg 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 3 of the License, or
// (at your option) any later version.
//
// MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
//
#include <UIKit/UIKit.h>
#include <mobileffmpeg/MediaInformationParser.h>
static NSString *MEDIA_INFORMATION_MP3;
static NSString *MEDIA_INFORMATION_JPG;
static NSString *MEDIA_INFORMATION_GIF;
static NSString *MEDIA_INFORMATION_H264;
static NSString *MEDIA_INFORMATION_PNG;
static NSString *MEDIA_INFORMATION_H264_2;
static NSString *MEDIA_INFORMATION_MP4;
static NSString *MEDIA_INFORMATION_MP4_2;
static NSString *MEDIA_INFORMATION_OGG;
static void initTests() {
MEDIA_INFORMATION_MP3 = [NSString stringWithFormat:
@"Unknown attached picture mimetype: audio/x-wav, skipping.\n"
"[mp3 @ 0x7ffb94805800] Estimating duration from bitrate, this may be inaccurate\n"
"Input #0, mp3, from 'beethoven_-_symphony_no_9.mp3':\n"
" Metadata:\n"
" comment : \n"
" album : Symphony No.9\n"
" compilation : 0\n"
" date : -1\n"
" title : Symphony No.9\n"
" artist : Beethoven\n"
" album_artist : Beethoven\n"
" track : -1\n"
" lyrics-XXX : \n"
" Duration: 00:03:33.24, start: 0.000000, bitrate: 320 kb/s\n"
" Stream #0:0: Audio: mp3, 48000 Hz, stereo, fltp, 320 kb/s\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (mp3 (mp3float) -> pcm_s16le (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" comment : \n"
" album : Symphony No.9\n"
" compilation : 0\n"
" date : -1\n"
" title : Symphony No.9\n"
" artist : Beethoven\n"
" album_artist : Beethoven\n"
" track : -1\n"
" lyrics-XXX : \n"
" encoder : Lavf58.12.100\n"
" Stream #0:0: Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s\n"
" Metadata:\n"
" encoder : Lavc58.18.100 pcm_s16le\n"
"size=N/A time=00:03:33.24 bitrate=N/A speed= 618x \n"
"video:0kB audio:39982kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"];
MEDIA_INFORMATION_JPG = [NSString stringWithFormat:
@"Input #0, image2, from '/data/user/0/com.arthenica.mobileffmpeg.test/cache/colosseum.jpg':\n"
" Duration: 00:00:00.04, start: 0.000000, bitrate: 391187 kb/s\n"
" Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 2560x1708 [SAR 1:1 DAR 640:427], 25 tbr, 25 tbn, 25 tbc\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (mjpeg (native) -> wrapped_avframe (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" encoder : Lavf58.18.104\n"
" Stream #0:0: Video: wrapped_avframe, yuvj420p, 2560x1708 [SAR 1:1 DAR 640:427], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc\n"
" Metadata:\n"
" encoder : Lavc58.31.102 wrapped_avframe\n"
"frame= 1 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=0.668x \n"
"video:0kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown\n"];
MEDIA_INFORMATION_GIF = [NSString stringWithFormat:
@"Input #0, gif, from 'advanced_zoom_in_and_pan_with_fade_in_out.gif':\n"
" Duration: N/A, bitrate: N/A\n"
" Stream #0:0: Video: gif, bgra, 420x236, 6 fps, 6 tbr, 100 tbn, 100 tbc\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (gif (native) -> wrapped_avframe (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" encoder : Lavf58.12.100\n"
" Stream #0:0: Video: wrapped_avframe, bgra, 420x236 [SAR 63:64 DAR 6615:3776], q=2-31, 200 kb/s, 6 fps, 6 tbn, 6 tbc\n"
" Metadata:\n"
" encoder : Lavc58.18.100 wrapped_avframe\n"
"frame= 61 fps=0.0 q=-0.0 Lsize=N/A time=00:00:10.16 bitrate=N/A speed= 219x \n"
"video:32kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"];
MEDIA_INFORMATION_H264 = [NSString stringWithFormat:
@"Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'transition_rotate.mp4':\n"
" Metadata:\n"
" major_brand : isom\n"
" minor_version : 512\n"
" compatible_brands: isomiso2avc1mp41\n"
" encoder : Lavf58.12.100\n"
" Duration: 00:00:15.00, start: 0.000000, bitrate: 7764 kb/s\n"
" Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 7762 kb/s, 25 fps, 30 tbr, 15360 tbn, 60 tbc (default)\n"
" Metadata:\n"
" handler_name : VideoHandler\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" major_brand : isom\n"
" minor_version : 512\n"
" compatible_brands: isomiso2avc1mp41\n"
" encoder : Lavf58.12.100\n"
" Stream #0:0(und): Video: wrapped_avframe, yuv420p, 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 30 fps, 30 tbn, 30 tbc (default)\n"
" Metadata:\n"
" handler_name : VideoHandler\n"
" encoder : Lavc58.18.100 wrapped_avframe\n"
"frame= 375 fps=0.0 q=-0.0 Lsize=N/A time=00:00:15.00 bitrate=N/A speed=35.9x \n"
"video:196kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"];
MEDIA_INFORMATION_PNG = [NSString stringWithFormat:
@"Input #0, png_pipe, from 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png':\n"
" Duration: N/A, bitrate: N/A\n"
" Stream #0:0: Video: png, rgba(pc), 544x184, 25 tbr, 25 tbn, 25 tbc\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (png (native) -> wrapped_avframe (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" encoder : Lavf58.12.100\n"
" Stream #0:0: Video: wrapped_avframe, rgba, 544x184, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc\n"
" Metadata:\n"
" encoder : Lavc58.18.100 wrapped_avframe\n"
"frame= 1 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=27.1x \n"
"video:1kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"];
MEDIA_INFORMATION_H264_2 = [NSString stringWithFormat:
@"Input #0, h264, from 'test.h264':\n"
" Duration: N/A, bitrate: N/A\n"
" Stream #0:0: Video: h264 (Main), yuv420p(tv, bt709, progressive), 1920x1080, 25 fps, 25 tbr, 1200k tbn, 50 tbc\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" encoder : Lavf58.12.100\n"
" Stream #0:0: Video: wrapped_avframe, yuv420p, 1920x1080, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc\n"
" Metadata:\n"
" encoder : Lavc58.18.100 wrapped_avframe\n"
"frame= 360 fps=0.0 q=-0.0 Lsize=N/A time=00:00:14.40 bitrate=N/A speed=25.5x \n"
"video:188kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"];
MEDIA_INFORMATION_MP4 = [NSString stringWithFormat:
@"Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_2160p_30fps_stereo_abl.mp4':\n"
" Metadata:\n"
" major_brand : isom\n"
" minor_version : 1\n"
" compatible_brands: isomavc1\n"
" creation_time : 2013-12-16T17:21:55.000000Z\n"
" title : Big Buck Bunny, Sunflower version\n"
" artist : Blender Foundation 2008, Janus Bager Kristensen 2013\n"
" comment : Creative Commons Attribution 3.0 - http://bbb3d.renderfarming.net\n"
" genre : Animation\n"
" composer : Sacha Goedegebure\n"
" Duration: 00:10:34.53, start: 0.000000, bitrate: 10385 kb/s\n"
" Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 3840x4320 [SAR 1:1 DAR 8:9], 9902 kb/s, 30 fps, 30 tbr, 30k tbn, 60 tbc (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:21:55.000000Z\n"
" handler_name : GPAC ISO Video Handler\n"
" Stream #0:1(und): Audio: mp3 (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:21:58.000000Z\n"
" handler_name : GPAC ISO Audio Handler\n"
" Stream #0:2(und): Audio: ac3 (ac-3 / 0x332D6361), 48000 Hz, 5.1(side), fltp, 320 kb/s (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:21:58.000000Z\n"
" handler_name : GPAC ISO Audio Handler\n"
" Side data:\n"
" audio service type: main\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))\n"
" Stream #0:2 -> #0:1 (ac3 (native) -> pcm_s16le (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" major_brand : isom\n"
" minor_version : 1\n"
" compatible_brands: isomavc1\n"
" composer : Sacha Goedegebure\n"
" title : Big Buck Bunny, Sunflower version\n"
" artist : Blender Foundation 2008, Janus Bager Kristensen 2013\n"
" comment : Creative Commons Attribution 3.0 - http://bbb3d.renderfarming.net\n"
" genre : Animation\n"
" encoder : Lavf58.12.100\n"
" Stream #0:0(und): Video: wrapped_avframe, yuv420p(progressive), 3840x4320 [SAR 1:1 DAR 8:9], q=2-31, 200 kb/s, 30 fps, 30 tbn, 30 tbc (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:21:55.000000Z\n"
" handler_name : GPAC ISO Video Handler\n"
" encoder : Lavc58.18.100 wrapped_avframe\n"
" Stream #0:1(und): Audio: pcm_s16le, 48000 Hz, 5.1(side), s16, 4608 kb/s (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:21:58.000000Z\n"
" handler_name : GPAC ISO Audio Handler\n"
" encoder : Lavc58.18.100 pcm_s16le\n"
" Side data:\n"
" audio service type: main\n"
"frame= 2798 fps= 85 q=-0.0 size=N/A time=00:01:33.33 bitrate=N/A speed=2.85x \n"];
MEDIA_INFORMATION_MP4_2 = [NSString stringWithFormat:
@"Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_stereo_arcd.mp4':\n"
" Metadata:\n"
" major_brand : isom\n"
" minor_version : 1\n"
" compatible_brands: isomavc1\n"
" creation_time : 2013-12-16T17:49:59.000000Z\n"
" title : Big Buck Bunny, Sunflower version\n"
" artist : Blender Foundation 2008, Janus Bager Kristensen 2013\n"
" comment : Creative Commons Attribution 3.0 - http://bbb3d.renderfarming.net\n"
" genre : Animation\n"
" composer : Sacha Goedegebure\n"
" Duration: 00:10:34.53, start: 0.000000, bitrate: 4474 kb/s\n"
" Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 3992 kb/s, 30 fps, 30 tbr, 30k tbn, 60 tbc (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:49:59.000000Z\n"
" handler_name : GPAC ISO Video Handler\n"
" Stream #0:1(und): Audio: mp3 (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:50:04.000000Z\n"
" handler_name : GPAC ISO Audio Handler\n"
" Stream #0:2(und): Audio: ac3 (ac-3 / 0x332D6361), 48000 Hz, 5.1(side), fltp, 320 kb/s (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:50:04.000000Z\n"
" handler_name : GPAC ISO Audio Handler\n"
" Side data:\n"
" audio service type: main\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))\n"
" Stream #0:2 -> #0:1 (ac3 (native) -> pcm_s16le (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" major_brand : isom\n"
" minor_version : 1\n"
" compatible_brands: isomavc1\n"
" composer : Sacha Goedegebure\n"
" title : Big Buck Bunny, Sunflower version\n"
" artist : Blender Foundation 2008, Janus Bager Kristensen 2013\n"
" comment : Creative Commons Attribution 3.0 - http://bbb3d.renderfarming.net\n"
" genre : Animation\n"
" encoder : Lavf58.12.100\n"
" Stream #0:0(und): Video: wrapped_avframe, yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 30 fps, 30 tbn, 30 tbc (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:49:59.000000Z\n"
" handler_name : GPAC ISO Video Handler\n"
" encoder : Lavc58.18.100 wrapped_avframe\n"
" Stream #0:1(und): Audio: pcm_s16le, 48000 Hz, 5.1(side), s16, 4608 kb/s (default)\n"
" Metadata:\n"
" creation_time : 2013-12-16T17:50:04.000000Z\n"
" handler_name : GPAC ISO Audio Handler\n"
" encoder : Lavc58.18.100 pcm_s16le\n"
" Side data:\n"
" audio service type: main\n"
"frame=19036 fps=401 q=-0.0 Lsize=N/A time=00:10:34.60 bitrate=N/A speed=13.4x \n"
"video:9964kB audio:356706kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"];
MEDIA_INFORMATION_OGG = [NSString stringWithFormat:
@"[theora @ 0x7fa30c026e00] 7 bits left in packet 82\n"
"[ogg @ 0x7fa30c005e00] Broken file, keyframe not correctly marked.\n"
"Input #0, ogg, from 'trailer_400p.ogg':\n"
" Duration: 00:00:33.00, start: 0.000000, bitrate: 1057 kb/s\n"
" Stream #0:0: Video: theora, yuv420p(bt470bg/bt470bg/bt709), 720x400, 25 fps, 25 tbr, 25 tbn, 25 tbc\n"
" Metadata:\n"
" ENCODER : ffmpeg2theora 0.19\n"
" Stream #0:1: Audio: vorbis, 48000 Hz, stereo, fltp, 80 kb/s\n"
" Metadata:\n"
" ENCODER : ffmpeg2theora 0.19\n"
"[theora @ 0x7fa30c1bd600] 7 bits left in packet 82\n"
"Stream mapping:\n"
" Stream #0:0 -> #0:0 (theora (native) -> wrapped_avframe (native))\n"
" Stream #0:1 -> #0:1 (vorbis (native) -> pcm_s16le (native))\n"
"Press [q] to stop, [?] for help\n"
"Output #0, null, to 'pipe:':\n"
" Metadata:\n"
" encoder : Lavf58.12.100\n"
" Stream #0:0: Video: wrapped_avframe, yuv420p(progressive), 720x400, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc\n"
" Metadata:\n"
" encoder : Lavc58.18.100 wrapped_avframe\n"
" Stream #0:1: Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s\n"
" Metadata:\n"
" encoder : Lavc58.18.100 pcm_s16le\n"
"[ogg @ 0x7fa30c005e00] Broken file, keyframe not correctly marked.\n"
" Last message repeated 5 times\n"
"frame= 813 fps=0.0 q=-0.0 Lsize=N/A time=00:00:33.01 bitrate=N/A speed= 234x \n"
"video:426kB audio:6190kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"];
}
void assertNumber(NSNumber *expected, NSNumber *real) {
if (expected == nil) {
assert(real == nil);
} else {
assert([expected isEqualToNumber:real]);
}
}
void assertString(NSString *expected, NSString *real) {
if (expected == nil) {
assert(real == nil);
} else {
assert([expected isEqualToString:real]);
}
}
void assertVideoStream(StreamInformation *stream, NSNumber *index, NSString *codec, NSString *fullCodec, NSString *format, NSString *fullFormat, NSNumber *width, NSNumber *height, NSString *sampleAspectRatio, NSString *displayAspectRatio, NSNumber *bitrate, NSString *averageFrameRate, NSString *realFrameRate, NSString *timeBase, NSString *codecTimeBase) {
assert(stream != nil);
assertNumber(index, [stream getIndex]);
assertString(@"video", [stream getType]);
assertString(codec, [stream getCodec]);
assertString(fullCodec, [stream getFullCodec]);
assertString(format, [stream getFormat]);
assertString(fullFormat, [stream getFullFormat]);
assertNumber(width, [stream getWidth]);
assertNumber(height, [stream getHeight]);
assertString(sampleAspectRatio, [stream getSampleAspectRatio]);
assertString(displayAspectRatio, [stream getDisplayAspectRatio]);
assertNumber(bitrate, [stream getBitrate]);
assertString(averageFrameRate, [stream getAverageFrameRate]);
assertString(realFrameRate, [stream getRealFrameRate]);
assertString(timeBase, [stream getTimeBase]);
assertString(codecTimeBase, [stream getCodecTimeBase]);
}
void parseVideoStreamBlock(NSString *input, NSNumber *index, NSString *codec, NSString *fullCodec, NSString *format, NSString *fullFormat, NSNumber *width, NSNumber *height, NSString *sampleAspectRatio, NSString *displayAspectRatio, NSNumber *bitrate, NSString *averageFrameRate, NSString *realFrameRate, NSString *timeBase, NSString *codecTimeBase) {
StreamInformation *stream = [MediaInformationParser parseStreamBlock:input];
assertVideoStream(stream, index, codec, fullCodec, format, fullFormat, width, height, sampleAspectRatio, displayAspectRatio, bitrate, averageFrameRate, realFrameRate, timeBase, codecTimeBase);
}
void assertAudioStream(StreamInformation *stream, NSNumber *index, NSString *codec, NSString *fullCodec, NSNumber *sampleRate, NSString *channelLayout, NSString *sampleFormat, NSNumber *bitrate) {
assert(stream != nil);
assertNumber(index, [stream getIndex]);
assertString(@"audio", [stream getType]);
assertString(codec, [stream getCodec]);
assertString(fullCodec, [stream getFullCodec]);
assertNumber(sampleRate, [stream getSampleRate]);
assertString(channelLayout, [stream getChannelLayout]);
assertString(sampleFormat, [stream getSampleFormat]);
assertNumber(bitrate, [stream getBitrate]);
}
void parseAudioStreamBlock(NSString *input, NSNumber *index, NSString *codec, NSString *fullCodec, NSNumber *sampleRate, NSString *channelLayout, NSString *sampleFormat, NSNumber *bitrate) {
StreamInformation *stream = [MediaInformationParser parseStreamBlock:input];
assertAudioStream(stream, index, codec, fullCodec, sampleRate, channelLayout, sampleFormat, bitrate);
}
void parseVideoDimensions(NSString *input, NSNumber *expectedWidth, NSNumber *expectedHeight) {
void(^pair)(NSNumber **, NSNumber **) = [MediaInformationParser parseVideoDimensions:input];
NSNumber *width;
NSNumber *height;
pair(&width, &height);
assert(pair != nil);
if (width == nil) {
assert(expectedWidth == nil);
} else {
assert([width isEqualToNumber:expectedWidth]);
}
if (height == nil) {
assert(expectedHeight == nil);
} else {
assert([height isEqualToNumber:expectedHeight]);
}
}
void parseDuration(NSString *input, NSNumber *expectedDuration) {
NSNumber *duration = [MediaInformationParser parseDuration:input];
if (duration == nil) {
assert(expectedDuration == nil);
} else {
assert([duration isEqualToNumber:expectedDuration]);
}
}
void parseStartTime(NSString *input, NSNumber *expectedStartTime) {
NSNumber *startTime = [MediaInformationParser parseStartTime:input];
if (startTime == nil) {
assert(expectedStartTime == nil);
} else {
assert([startTime isEqualToNumber:expectedStartTime]);
}
}
void parseDurationBlock(NSString *input, NSNumber *expectedDuration, NSNumber *expectedStartTime, NSNumber *expectedBitrate) {
void(^trio)(NSNumber **, NSNumber **, NSNumber **) = [MediaInformationParser parseDurationBlock:input];
NSNumber *duration;
NSNumber *startTime;
NSNumber *bitrate;
trio(&duration, &startTime, &bitrate);
assert(trio != nil);
if (duration == nil) {
assert(expectedDuration == nil);
} else {
assert([duration isEqualToNumber:expectedDuration]);
}
if (startTime == nil) {
assert(expectedStartTime == nil);
} else {
assert([startTime isEqualToNumber:expectedStartTime]);
}
if (bitrate == nil) {
assert(expectedBitrate == nil);
} else {
assert([bitrate isEqualToNumber:expectedBitrate]);
}
}
void parseMetadataBlock(NSString *input, NSString *expectedKey, NSString *expectedValue) {
void(^pair)(NSString **, NSString **) = [MediaInformationParser parseMetadataBlock:input];
NSString *key;
NSString *value;
pair(&key, &value);
assert(pair != nil);
assert(key != nil);
assert(value != nil);
assert([key isEqualToString:expectedKey]);
assert([value isEqualToString:expectedValue]);
}
void parseInputBlock(NSString *input, NSString *expectedFormat, NSString *expectedPath) {
void(^pair)(NSString **, NSString **) = [MediaInformationParser parseInputBlock:input];
NSString *format;
NSString *path;
pair(&format, &path);
assert(pair != nil);
if (format == nil) {
assert(expectedFormat == nil);
} else {
assert([format isEqualToString:expectedFormat]);
}
if (path == nil) {
assert(expectedPath == nil);
} else {
assert([path isEqualToString:expectedPath]);
}
}
void testParseVideoStream() {
parseVideoStreamBlock(@" Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 2560x1708 [SAR 1:1 DAR 640:427], 25 tbr, 25 tbn, 25 tbc", [[NSNumber alloc] initWithInt:0], @"mjpeg", @"mjpeg", @"yuvj420p", @"yuvj420p(pc, bt470bg/unknown/unknown)", [[NSNumber alloc] initWithInt:2560], [[NSNumber alloc] initWithInt:1708], @"1:1", @"640:427", nil, nil, @"25", @"25", @"25");
parseVideoStreamBlock(@" Stream #0:0: Video: gif, bgra, 420x236, 6 fps, 6 tbr, 100 tbn, 100 tbc", [[NSNumber alloc] initWithInt:0], @"gif", @"gif", @"bgra", @"bgra", [[NSNumber alloc] initWithInt:420], [[NSNumber alloc] initWithInt:236], nil, nil, nil, @"6", @"6", @"100", @"100");
parseVideoStreamBlock(@" Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 7762 kb/s, 25 fps, 30 tbr, 15360 tbn, 60 tbc (default)", [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (main) (avc1 / 0x31637661)", @"yuv420p", @"yuv420p", [[NSNumber alloc] initWithInt:1280], [[NSNumber alloc] initWithInt:720], @"1:1", @"16:9", [[NSNumber alloc] initWithInt:7762], @"25", @"30", @"15360", @"60");
parseVideoStreamBlock(@" Stream #0:0: Video: png, rgba(pc), 544x184, 25 tbr, 25 tbn, 25 tbc", [[NSNumber alloc] initWithInt:0], @"png", @"png", @"rgba", @"rgba(pc)", [[NSNumber alloc] initWithInt:544], [[NSNumber alloc] initWithInt:184], nil, nil, nil, nil, @"25", @"25", @"25");
parseVideoStreamBlock(@" Stream #0:0: Video: h264 (Main), yuv420p(tv, bt709, progressive), 1920x1080, 25 fps, 25 tbr, 1200k tbn, 50 tbc", [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (main)", @"yuv420p", @"yuv420p(tv, bt709, progressive)", [[NSNumber alloc] initWithInt:1920], [[NSNumber alloc] initWithInt:1080], nil, nil, nil, @"25", @"25", @"1200k", @"50");
parseVideoStreamBlock(@" Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 3840x4320 [SAR 1:1 DAR 8:9], 9902 kb/s, 30 fps, 30 tbr, 30k tbn, 60 tbc (default)", [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (high) (avc1 / 0x31637661)", @"yuv420p", @"yuv420p", [[NSNumber alloc] initWithInt:3840], [[NSNumber alloc] initWithInt:4320], @"1:1", @"8:9", [[NSNumber alloc] initWithInt:9902], @"30", @"30", @"30k", @"60");
parseVideoStreamBlock(@" Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 3992 kb/s, 30 fps, 30 tbr, 30k tbn, 60 tbc (default)", [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (high) (avc1 / 0x31637661)", @"yuv420p", @"yuv420p", [[NSNumber alloc] initWithInt:1920], [[NSNumber alloc] initWithInt:1080], @"1:1", @"16:9", [[NSNumber alloc] initWithInt:3992], @"30", @"30", @"30k", @"60");
parseVideoStreamBlock(@" Stream #0:0: Video: theora, yuv420p(bt470bg/bt470bg/bt709), 720x400, 25 fps, 25 tbr, 25 tbn, 25 tbc", [[NSNumber alloc] initWithInt:0], @"theora", @"theora", @"yuv420p", @"yuv420p(bt470bg/bt470bg/bt709)", [[NSNumber alloc] initWithInt:720], [[NSNumber alloc] initWithInt:400], nil, nil, nil, @"25", @"25", @"25", @"25");
}
void testParseAudioStream() {
parseAudioStreamBlock(@"Stream #0:0: Audio: adpcm_ms ([2][0][0][0] / 0x0002), 22050 Hz, stereo, s16, 176 kb/s", [[NSNumber alloc] initWithInt:0], @"adpcm_ms", @"adpcm_ms ([2][0][0][0] / 0x0002)", [[NSNumber alloc] initWithInt:22050], @"stereo", @"s16", [[NSNumber alloc] initWithInt:176]);
parseAudioStreamBlock(@"Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, mono, s16, 705 kb/s",[[NSNumber alloc] initWithInt:0], @"pcm_s16le", @"pcm_s16le ([1][0][0][0] / 0x0001)", [[NSNumber alloc] initWithInt:44100], @"mono", @"s16", [[NSNumber alloc] initWithInt:705]);
parseAudioStreamBlock(@"Stream #0:0: Audio: pcm_s24le ([1][0][0][0] / 0x0001), 48000 Hz, mono, s32 (24 bit), 1152 kb/s", [[NSNumber alloc] initWithInt:0], @"pcm_s24le", @"pcm_s24le ([1][0][0][0] / 0x0001)", [[NSNumber alloc] initWithInt:48000], @"mono", @"s32 (24 bit)", [[NSNumber alloc] initWithInt:1152]);
parseAudioStreamBlock(@"Stream #0:0: Audio: mp3, 48000 Hz, stereo, fltp, 192 kb/s", [[NSNumber alloc] initWithInt:0], @"mp3", @"mp3", [[NSNumber alloc] initWithInt:48000], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:192]);
parseAudioStreamBlock(@"Stream #0:0: Audio: vorbis, 44100 Hz, stereo, fltp, 128 kb/s", [[NSNumber alloc] initWithInt:0], @"vorbis", @"vorbis", [[NSNumber alloc] initWithInt:44100], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:128]);
parseAudioStreamBlock(@"Stream #0:0: Audio: pcm_u8 ([1][0][0][0] / 0x0001), 44100 Hz, stereo, u8, 705 kb/s", [[NSNumber alloc] initWithInt:0], @"pcm_u8", @"pcm_u8 ([1][0][0][0] / 0x0001)", [[NSNumber alloc] initWithInt:44100], @"stereo", @"u8", [[NSNumber alloc] initWithInt:705]);
parseAudioStreamBlock(@"Stream #0:1(und): Audio: mp3 (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s (default)", [[NSNumber alloc] initWithInt:1], @"mp3", @"mp3 (mp4a / 0x6134706d)", [[NSNumber alloc] initWithInt:48000], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:160]);
parseAudioStreamBlock(@"Stream #0:2(und): Audio: ac3 (ac-3 / 0x332D6361), 48000 Hz, 5.1(side), fltp, 320 kb/s (default)", [[NSNumber alloc] initWithInt:2], @"ac3", @"ac3 (ac-3 / 0x332d6361)", [[NSNumber alloc] initWithInt:48000], @"5.1(side)", @"fltp", [[NSNumber alloc] initWithInt:320]);
parseAudioStreamBlock(@"Stream #0:1(und): Audio: mp3 (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s (default)", [[NSNumber alloc] initWithInt:1], @"mp3", @"mp3 (mp4a / 0x6134706d)", [[NSNumber alloc] initWithInt:48000], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:160]);
parseAudioStreamBlock(@"Stream #0:2(und): Audio: ac3 (ac-3 / 0x332D6361), 48000 Hz, 5.1(side), fltp, 320 kb/s (default)", [[NSNumber alloc] initWithInt:2], @"ac3", @"ac3 (ac-3 / 0x332d6361)", [[NSNumber alloc] initWithInt:48000], @"5.1(side)", @"fltp", [[NSNumber alloc] initWithInt:320]);
}
void testIndex() {
assert(7 == [MediaInformationParser index:@"one:two:three:" of:@":" from:0 times:2]);
assert(13 == [MediaInformationParser index:@"one:two:three:" of:@":" from:0 times:3]);
assert(8 == [MediaInformationParser index:@"one::two::three::" of:@"::" from:0 times:2]);
}
void testCount() {
assert(3 == [MediaInformationParser count:@"one:two:three:" of:@":"]);
assert(2 == [MediaInformationParser count:@"one,two:three,four" of:@","]);
}
void testParseVideoStreamDisplayAspectRatio() {
assert(nil == [MediaInformationParser parseVideoStreamDisplayAspectRatio:@""]);
assert(nil == [MediaInformationParser parseVideoStreamDisplayAspectRatio:@"544x184"]);
assert([@"640:427" isEqualToString:[MediaInformationParser parseVideoStreamDisplayAspectRatio:@"2560x1708 [SAR 1:1 DAR 640:427]"]]);
assert([@"8:9" isEqualToString:[MediaInformationParser parseVideoStreamDisplayAspectRatio:@"3840x4320 [SAR 1:1 DAR 8:9]"]]);
}
void testParseVideoStreamSampleAspectRatio() {
assert(nil == [MediaInformationParser parseVideoStreamSampleAspectRatio:@""]);
assert(nil == [MediaInformationParser parseVideoStreamSampleAspectRatio:@"544x184"]);
assert([@"1:1" isEqualToString:[MediaInformationParser parseVideoStreamSampleAspectRatio:@"2560x1708 [SAR 1:1 DAR 640:427]"]]);
assert([@"1:1" isEqualToString:[MediaInformationParser parseVideoStreamSampleAspectRatio:@"3840x4320 [SAR 1:1 DAR 8:9]"]]);
}
void testParseVideoDimensions() {
parseVideoDimensions(@"", nil, nil);
parseVideoDimensions(@"544x184", [[NSNumber alloc] initWithInt:544], [[NSNumber alloc] initWithInt:184]);
parseVideoDimensions(@"720x400", [[NSNumber alloc] initWithInt:720], [[NSNumber alloc] initWithInt:400]);
parseVideoDimensions(@"2560x1708 [SAR 1:1 DAR 640:427]", [[NSNumber alloc] initWithInt:2560], [[NSNumber alloc] initWithInt:1708]);
parseVideoDimensions(@"3840x4320 [SAR 1:1 DAR 8:9]", [[NSNumber alloc] initWithInt:3840], [[NSNumber alloc] initWithInt:4320]);
}
void testParseAudioSampleRate() {
assert([[[NSNumber alloc] initWithInt:44000] isEqualToNumber:[MediaInformationParser parseAudioStreamSampleRate:@"44000"]]);
assert([[[NSNumber alloc] initWithInt:44000] isEqualToNumber:[MediaInformationParser parseAudioStreamSampleRate:@"44 khz"]]);
assert([[[NSNumber alloc] initWithInt:44100] isEqualToNumber:[MediaInformationParser parseAudioStreamSampleRate:@"44100"]]);
assert([[[NSNumber alloc] initWithInt:5000000] isEqualToNumber:[MediaInformationParser parseAudioStreamSampleRate:@"5 mhz"]]);
}
void testParseAudioStreamType() {
assert([@"video" isEqualToString:[MediaInformationParser parseStreamType:@"Video: theora"]]);
assert([@"video" isEqualToString:[MediaInformationParser parseStreamType:@"Video: png"]]);
assert([@"video" isEqualToString:[MediaInformationParser parseStreamType:@"Video: h264 (Main)"]]);
assert([@"audio" isEqualToString:[MediaInformationParser parseStreamType:@"Audio: adpcm_ms ([2][0][0][0] / 0x0002)"]]);
assert([@"audio" isEqualToString:[MediaInformationParser parseStreamType:@"Audio: mp3 (mp4a / 0x6134706D)"]]);
assert([@"audio" isEqualToString:[MediaInformationParser parseStreamType:@"Audio: pcm_u8 ([1][0][0][0] / 0x0001)"]]);
}
void testParseStreamCodec() {
assert([@"theora" isEqualToString:[MediaInformationParser parseStreamCodec:@"Video: theora"]]);
assert([@"png" isEqualToString:[MediaInformationParser parseStreamCodec:@"Video: png"]]);
assert([@"h264" isEqualToString:[MediaInformationParser parseStreamCodec:@"Video: h264 (Main)"]]);
assert([@"adpcm_ms" isEqualToString:[MediaInformationParser parseStreamCodec:@"Audio: adpcm_ms ([2][0][0][0] / 0x0002)"]]);
assert([@"mp3" isEqualToString:[MediaInformationParser parseStreamCodec:@"Audio: mp3 (mp4a / 0x6134706D)"]]);
assert([@"pcm_u8" isEqualToString:[MediaInformationParser parseStreamCodec:@"Audio: pcm_u8 ([1][0][0][0] / 0x0001)"]]);
}
void testParseStreamFullCodec() {
assert([@"theora" isEqualToString:[MediaInformationParser parseStreamFullCodec:@"Video: theora"]]);
assert([@"png" isEqualToString:[MediaInformationParser parseStreamFullCodec:@"Video: png"]]);
assert([@"h264 (main)" isEqualToString:[MediaInformationParser parseStreamFullCodec:@"Video: h264 (Main)"]]);
assert([@"adpcm_ms ([2][0][0][0] / 0x0002)" isEqualToString:[MediaInformationParser parseStreamFullCodec:@"Audio: adpcm_ms ([2][0][0][0] / 0x0002)"]]);
assert([@"mp3 (mp4a / 0x6134706d)" isEqualToString:[MediaInformationParser parseStreamFullCodec:@"Audio: mp3 (mp4a / 0x6134706D)"]]);
assert([@"pcm_u8 ([1][0][0][0] / 0x0001)" isEqualToString:[MediaInformationParser parseStreamFullCodec:@"Audio: pcm_u8 ([1][0][0][0] / 0x0001)"]]);
}
void testParseStreamIndex() {
assert([[[NSNumber alloc] initWithInt: 0] isEqualToNumber:[MediaInformationParser parseStreamIndex:@"Stream #0:0(und): Audio"]]);
assert([[[NSNumber alloc] initWithInt: 1] isEqualToNumber:[MediaInformationParser parseStreamIndex:@"Stream #0:1(und): Video"]]);
assert([[[NSNumber alloc] initWithInt: 2] isEqualToNumber:[MediaInformationParser parseStreamIndex:@"Stream #0:2(und): Audio"]]);
assert([[[NSNumber alloc] initWithInt: 0] isEqualToNumber:[MediaInformationParser parseStreamIndex:@"Stream #0:0: Video"]]);
assert([[[NSNumber alloc] initWithInt: 1] isEqualToNumber:[MediaInformationParser parseStreamIndex:@"Stream #0:1: Audio"]]);
assert([[[NSNumber alloc] initWithInt: 2] isEqualToNumber:[MediaInformationParser parseStreamIndex:@"Stream #0:2: Video"]]);
}
void testParseDuration() {
parseDuration(nil, nil);
parseDuration(@"", nil);
parseDuration(@"N/A", nil);
parseDuration(@"00:03:33.24", [[NSNumber alloc] initWithInt: 213240]);
parseDuration(@"00:10:34.53", [[NSNumber alloc] initWithInt: 634530]);
parseDuration(@"00:00:00.04", [[NSNumber alloc] initWithInt: 40]);
parseDuration(@"00:00:15.00", [[NSNumber alloc] initWithInt: 15000]);
}
void testParseStartTime() {
parseStartTime(nil, nil);
parseStartTime(@"", nil);
parseStartTime(@"N/A", nil);
parseStartTime(@"0.000000", [[NSNumber alloc] initWithInt:0]);
parseStartTime(@"10.003000", [[NSNumber alloc] initWithInt:10003]);
parseStartTime(@"324.000000", [[NSNumber alloc] initWithInt:324000]);
parseStartTime(@"-4.000000", [[NSNumber alloc] initWithInt:-4000]);
parseStartTime(@"14.00030", [[NSNumber alloc] initWithInt:14001]);
parseStartTime(@"14.00080", [[NSNumber alloc] initWithInt:14001]);
}
void testParseDurationBlock() {
parseDurationBlock(@" Duration: 00:03:33.24, start: 0.000000, bitrate: 320 kb/s", [[NSNumber alloc] initWithInt:213240], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:320]);
parseDurationBlock(@" Duration: 00:00:00.04, start: 0.000000, bitrate: 391187 kb/s", [[NSNumber alloc] initWithInt:40], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:391187]);
parseDurationBlock(@" Duration: N/A, bitrate: N/A", nil, nil, nil);
parseDurationBlock(@" Duration: 00:00:15.00, start: 0.000000, bitrate: 7764 kb/s", [[NSNumber alloc] initWithInt:15000], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:7764]);
parseDurationBlock(@" Duration: 00:10:34.53, start: 0.000000, bitrate: 4474 kb/s", [[NSNumber alloc] initWithInt:634530], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:4474]);
}
void testParseInputBlock() {
parseInputBlock(@"Input #0,", nil, nil);
parseInputBlock(@"Input #0, ogg, from 'trailer_400p.ogg':", @"ogg", @"trailer_400p.ogg");
parseInputBlock(@"Input #0, mp3, from 'beethoven_-_symphony_no_9.mp3':", @"mp3", @"beethoven_-_symphony_no_9.mp3");
parseInputBlock(@"Input #0, image2, from '/data/user/0/com.arthenica.mobileffmpeg.test/cache/colosseum.jpg':", @"image2", @"/data/user/0/com.arthenica.mobileffmpeg.test/cache/colosseum.jpg");
parseInputBlock(@"Input #0, gif, from 'advanced_zoom_in_and_pan_with_fade_in_out.gif':", @"gif", @"advanced_zoom_in_and_pan_with_fade_in_out.gif");
parseInputBlock(@"Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'transition_rotate.mp4':", @"mov,mp4,m4a,3gp,3g2,mj2", @"transition_rotate.mp4");
parseInputBlock(@"Input #0, png_pipe, from 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png':", @"png_pipe", @"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png");
}
void testParseMetadataBlock() {
parseMetadataBlock(@" ENCODER:", @"ENCODER", @"");
parseMetadataBlock(@" ENCODER:ffmpeg2theora 0.19", @"ENCODER", @"ffmpeg2theora 0.19");
parseMetadataBlock(@" ENCODER : ffmpeg2theora 0.19", @"ENCODER", @"ffmpeg2theora 0.19");
parseMetadataBlock(@" creation_time : 2013-12-16T17:50:04.000000Z", @"creation_time", @"2013-12-16T17:50:04.000000Z");
parseMetadataBlock(@" handler_name : GPAC ISO Audio Handler", @"handler_name", @"GPAC ISO Audio Handler");
parseMetadataBlock(@" comment : Creative Commons Attribution 3.0 - http://bbb3d.renderfarming.net", @"comment", @"Creative Commons Attribution 3.0 - http://bbb3d.renderfarming.net");
parseMetadataBlock(@" minor_version : 1", @"minor_version", @"1");
parseMetadataBlock(@" encoder : Lavf58.12.100", @"encoder", @"Lavf58.12.100");
parseMetadataBlock(@" title : Planet X", @"title", @"Planet X");
parseMetadataBlock(@" compatible_brands: isomiso2avc1mp41", @"compatible_brands", @"isomiso2avc1mp41");
}
void assertNotNull(NSObject *object) {
assert(object != nil);
}
void assertMediaInput(MediaInformation *mediaInformation, NSString *expectedFormat, NSString *expectedPath) {
NSString *format = [mediaInformation getFormat];
NSString *path = [mediaInformation getPath];
if (format == nil) {
assert(expectedFormat == nil);
} else {
assert([format isEqualToString:expectedFormat]);
}
if (path == nil) {
assert(expectedPath == nil);
} else {
assert([path isEqualToString:expectedPath]);
}
}
void assertMediaDuration(MediaInformation *mediaInformation, NSNumber *expectedDuration, NSNumber *expectedStartTime, NSNumber *expectedBitrate) {
NSNumber *duration = [mediaInformation getDuration];
NSNumber *startTime = [mediaInformation getStartTime];
NSNumber *bitrate = [mediaInformation getBitrate];
if (duration == nil) {
assert(expectedDuration == nil);
} else {
assert([duration isEqualToNumber:expectedDuration]);
}
if (startTime == nil) {
assert(expectedStartTime == nil);
} else {
assert([startTime isEqualToNumber:expectedStartTime]);
}
if (bitrate == nil) {
assert(expectedBitrate == nil);
} else {
assert([bitrate isEqualToNumber:expectedBitrate]);
}
}
void testMediaInformationMp3() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_MP3];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"mp3", @"beethoven_-_symphony_no_9.mp3");
assertMediaDuration(mediaInformation, [[NSNumber alloc] initWithInt: 213240], [[NSNumber alloc] initWithInt: 0], [[NSNumber alloc] initWithInt: 320]);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(1 == [streams count]);
assertAudioStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"mp3", @"mp3", [[NSNumber alloc] initWithInt:48000], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:320]);
}
void testMediaInformationJpg() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_JPG];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"image2", @"/data/user/0/com.arthenica.mobileffmpeg.test/cache/colosseum.jpg");
assertMediaDuration(mediaInformation, [[NSNumber alloc] initWithInt:40], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:391187]);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(1 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"mjpeg", @"mjpeg", @"yuvj420p", @"yuvj420p(pc, bt470bg/unknown/unknown)", [[NSNumber alloc] initWithInt:2560], [[NSNumber alloc] initWithInt:1708], @"1:1", @"640:427", nil, nil, @"25", @"25", @"25");
}
void testMediaInformationGif() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_GIF];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"gif", @"advanced_zoom_in_and_pan_with_fade_in_out.gif");
assertMediaDuration(mediaInformation, nil, nil, nil);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(1 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"gif", @"gif", @"bgra", @"bgra", [[NSNumber alloc] initWithInt:420], [[NSNumber alloc] initWithInt:236], nil, nil, nil, @"6", @"6", @"100", @"100");
}
void testMediaInformationH264() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_H264];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"mov,mp4,m4a,3gp,3g2,mj2", @"transition_rotate.mp4");
assertMediaDuration(mediaInformation, [[NSNumber alloc] initWithInt:15000], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:7764]);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(1 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (main) (avc1 / 0x31637661)", @"yuv420p", @"yuv420p", [[NSNumber alloc] initWithInt:1280], [[NSNumber alloc] initWithInt:720], @"1:1", @"16:9", [[NSNumber alloc] initWithInt:7762], @"25", @"30", @"15360", @"60");
}
void testMediaInformationPng() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_PNG];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"png_pipe", @"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png");
assertMediaDuration(mediaInformation, nil, nil, nil);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(1 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"png", @"png", @"rgba", @"rgba(pc)", [[NSNumber alloc] initWithInt:544], [[NSNumber alloc] initWithInt:184], nil, nil, nil, nil, @"25", @"25", @"25");
}
void testMediaInformationH2642() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_H264_2];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"h264", @"test.h264");
assertMediaDuration(mediaInformation, nil, nil, nil);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(1 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (main)", @"yuv420p", @"yuv420p(tv, bt709, progressive)", [[NSNumber alloc] initWithInt:1920], [[NSNumber alloc] initWithInt:1080], nil, nil, nil, @"25", @"25", @"1200k", @"50");
}
void testMediaInformationMp4() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_MP4];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"mov,mp4,m4a,3gp,3g2,mj2", @"http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_2160p_30fps_stereo_abl.mp4");
assertMediaDuration(mediaInformation, [[NSNumber alloc] initWithInt:634530], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:10385]);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(3 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (high) (avc1 / 0x31637661)", @"yuv420p", @"yuv420p", [[NSNumber alloc] initWithInt:3840], [[NSNumber alloc] initWithInt:4320], @"1:1", @"8:9", [[NSNumber alloc] initWithInt:9902], @"30", @"30", @"30k", @"60");
assertAudioStream([streams objectAtIndex:1], [[NSNumber alloc] initWithInt:1], @"mp3", @"mp3 (mp4a / 0x6134706d)", [[NSNumber alloc] initWithInt:48000], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:160]);
assertAudioStream([streams objectAtIndex:2], [[NSNumber alloc] initWithInt:2], @"ac3", @"ac3 (ac-3 / 0x332d6361)", [[NSNumber alloc] initWithInt:48000], @"5.1(side)", @"fltp", [[NSNumber alloc] initWithInt:320]);
}
void testMediaInformationMp42() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_MP4_2];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"mov,mp4,m4a,3gp,3g2,mj2", @"http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_stereo_arcd.mp4");
assertMediaDuration(mediaInformation, [[NSNumber alloc] initWithInt:634530], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:4474]);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(3 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"h264", @"h264 (high) (avc1 / 0x31637661)", @"yuv420p", @"yuv420p", [[NSNumber alloc] initWithInt:1920], [[NSNumber alloc] initWithInt:1080], @"1:1", @"16:9", [[NSNumber alloc] initWithInt:3992], @"30", @"30", @"30k", @"60");
assertAudioStream([streams objectAtIndex:1], [[NSNumber alloc] initWithInt:1], @"mp3", @"mp3 (mp4a / 0x6134706d)", [[NSNumber alloc] initWithInt:48000], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:160]);
assertAudioStream([streams objectAtIndex:2], [[NSNumber alloc] initWithInt:2], @"ac3", @"ac3 (ac-3 / 0x332d6361)", [[NSNumber alloc] initWithInt:48000], @"5.1(side)", @"fltp", [[NSNumber alloc] initWithInt:320]);
}
void testMediaInformationOgg() {
MediaInformation *mediaInformation = [MediaInformationParser from:MEDIA_INFORMATION_OGG];
assertNotNull(mediaInformation);
assertMediaInput(mediaInformation, @"ogg", @"trailer_400p.ogg");
assertMediaDuration(mediaInformation, [[NSNumber alloc] initWithInt:33000], [[NSNumber alloc] initWithInt:0], [[NSNumber alloc] initWithInt:1057]);
NSArray *streams = [mediaInformation getStreams];
assertNotNull(streams);
assert(2 == [streams count]);
assertVideoStream([streams objectAtIndex:0], [[NSNumber alloc] initWithInt:0], @"theora", @"theora", @"yuv420p", @"yuv420p(bt470bg/bt470bg/bt709)", [[NSNumber alloc] initWithInt:720], [[NSNumber alloc] initWithInt:400], nil, nil, nil, @"25", @"25", @"25", @"25");
assertAudioStream([streams objectAtIndex:1], [[NSNumber alloc] initWithInt:1], @"vorbis", @"vorbis", [[NSNumber alloc] initWithInt:48000], @"stereo", @"fltp", [[NSNumber alloc] initWithInt:80]);
}
/**
* All parsing tests are initiated from this method
*/
void runMediaInformationParserTests() {
initTests();
testParseMetadataBlock();
testParseInputBlock();
testParseDurationBlock();
testParseStartTime();
testParseDuration();
testParseStreamIndex();
testParseStreamFullCodec();
testParseStreamCodec();
testParseAudioStreamType();
testParseAudioSampleRate();
testParseVideoDimensions();
testParseVideoStreamSampleAspectRatio();
testParseVideoStreamDisplayAspectRatio();
testCount();
testIndex();
testParseAudioStream();
testParseVideoStream();
testMediaInformationMp3();
testMediaInformationJpg();
testMediaInformationGif();
testMediaInformationH264();
testMediaInformationPng();
testMediaInformationH2642();
testMediaInformationMp4();
testMediaInformationMp42();
testMediaInformationOgg();
NSLog(@"MediaInformationParserTests passed.");
}
+6
View File
@@ -20,10 +20,16 @@
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "MediaInformationParserTests.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
// RUN UNIT TESTS BEFORE STARTING THE APPLICATION
runMediaInformationParserTests();
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}