Используйте приведенный ниже метод для установки правильной ориентации в соответствии с ориентацией видеообъекта в AVMutableVideoComposition
-(AVMutableVideoComposition *) getVideoComposition:(AVAsset *)asset
{
AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
CGSize videoSize = videoTrack.naturalSize;
BOOL isPortrait_ = [self isVideoPortrait:asset];
if(isPortrait_) {
NSLog(@"video is portrait ");
videoSize = CGSizeMake(videoSize.height, videoSize.width);
}
composition.naturalSize = videoSize;
videoComposition.renderSize = videoSize;
// videoComposition.renderSize = videoTrack.naturalSize; //
videoComposition.frameDuration = CMTimeMakeWithSeconds( 1 / videoTrack.nominalFrameRate, 600);
AVMutableCompositionTrack *compositionVideoTrack;
compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil];
AVMutableVideoCompositionLayerInstruction *layerInst;
layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero];
AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
inst.layerInstructions = [NSArray arrayWithObject:layerInst];
videoComposition.instructions = [NSArray arrayWithObject:inst];
return videoComposition;
}
-(BOOL) isVideoPortrait:(AVAsset *)asset
{
BOOL isPortrait = FALSE;
NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
if([tracks count] > 0) {
AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
CGAffineTransform t = videoTrack.preferredTransform;
// Portrait
if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0)
{
isPortrait = YES;
}
// PortraitUpsideDown
if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0) {
isPortrait = YES;
}
// LandscapeRight
if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0)
{
isPortrait = NO;
}
// LandscapeLeft
if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0)
{
isPortrait = NO;
}
}
return isPortrait;
}
См. Ленивая обработка ошибок в Java для обзора того, как исключить блоки try / catch с использованием типа Option
.
Функциональная Java - ваш друг.
По сути, вы хотите заключить синтаксический анализ даты в функцию, которая ничего не генерирует, но указывает в своем возвращаемом типе, был ли синтаксический анализ успешным или нет. Например:
import fj.F; import fj.F2;
import fj.data.Option;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import static fj.Function.curry;
import static fj.Option.some;
import static fj.Option.none;
...
F<String, F<String, Option<Date>>> parseDate =
curry(new F2<String, String, Option<Date>>() {
public Option<Date> f(String pattern, String s) {
try {
return some(new SimpleDateFormat(pattern).parse(s));
}
catch (ParseException e) {
return none();
}
}
});
Хорошо, теперь у вас есть многоразовый синтаксический анализатор даты, который ничего не выдает, но указывает на сбой, возвращая значение типа Option.None
. Вот как вы его используете:
import fj.data.List;
import static fj.data.Stream.stream;
import static fj.data.Option.isSome_;
....
public Option<Date> parseWithPatterns(String s, Stream<String> patterns) {
return stream(s).apply(patterns.map(parseDate)).find(isSome_());
}
Это даст вам дату, проанализированную с первым совпадающим шаблоном, или значение типа Option.None, которое является типобезопасным, тогда как null - нет.
Если вы интересно, что такое Stream
... it ' в ленивом списке . Это гарантирует, что вы игнорируете шаблоны после первого успешного. Не нужно делать слишком много работы.
Назовите свою функцию так:
for (Date d: parseWithPatterns(someString, stream("dd/MM/yyyy", "dd-MM-yyyy")) {
// Do something with the date here.
}
Или ...
Option<Date> d = parseWithPatterns(someString,
stream("dd/MM/yyyy", "dd-MM-yyyy"));
if (d.isNone()) {
// Handle the case where neither pattern matches.
}
else {
// Do something with d.some()
}
Не относитесь к себе слишком строго, используя try-catch в логике: это одна из тех ситуаций, когда Java вынуждает вас делать это, так что вы мало что можете с этим поделать.
Но в этом случае вы можете вместо этого использовать DateFormat.parse (String, ParsePosition)
.
Вы можете воспользоваться регулярными выражениями, чтобы определить, в каком формате находится строка и соответствует ли она какому-либо допустимому формату. Примерно так (не проверено):
(К сожалению, я написал это на C #, прежде чем проверять, какой язык вы используете.)
Regex test = new Regex(@"^(?:(?<formatA>\d{2}-[a-zA-Z]{3}-\d{2})|(?<formatB>\d{2}/\d{2}/\d{3}))$", RegexOption.Compiled);
Match match = test.Match(yourString);
if (match.Success)
{
if (!string.IsNullOrEmpty(match.Groups["formatA"]))
{
// Use format A.
}
else if (!string.IsNullOrEmpty(match.Groups["formatB"]))
{
// Use format B.
}
...
}
Если форматы точны (7 июня 1999 г. будет либо 07 июня 1999 г., либо 06.07.1999: вы уверены, что у вас есть ведущие нули), тогда вы можете просто проверьте длину строки перед попыткой синтаксического анализа.
Будьте осторожны с коротким названием месяца в первой версии, потому что июнь может не быть июнем на другом языке.
Но если ваши данные приходят. из одной базы данных, тогда я бы просто преобразовал все даты в общий формат (он разовый, но затем вы управляете данными и их форматом).
В этой ограниченной ситуации лучший (и самый быстрый метод) - это определенно проанализировать день, а затем на основе следующего символа '/' или '-' попытаться проанализировать остальные . и если в какой-то момент появятся неожиданные данные, тогда верните NULL.
Похоже, три варианта, если у вас есть только два известных формата:
-
или /
сначала и начните с этого синтаксического анализа для этого формата. ] Последнее кажется ненужным.
Используйте регулярные выражения для анализа вашей строки. Убедитесь, что оба регулярных выражения предварительно скомпилированы (не создавайте новые при каждом вызове метода, а сохраняете их как константы), и сравните, действительно ли оно быстрее, чем используемый вами try-catch
.
Мне все еще кажется странным, что ваш метод возвращает null
, если обе версии терпят неудачу, а не генерирует исключение.
вы можете использовать разделение, чтобы определить, какой формат использовать
String[] parts = date.split("-");
df = (parts.length==3 ? format1 : format2);
Предполагается, что все они находятся в том или ином формате, вы можете улучшить проверку, если это необходимо
Предполагая, что предоставленные вами шаблоны являются единственно вероятным выбором, я бы посмотрел на переданную строку, чтобы увидеть, какой формат применить.
public Date parseDate(final String date) {
if (date == null) {
return null;
}
SimpleDateFormat format = (date.charAt(2) == '/') ? new SimpleDateFormat("dd/MMM/yyyy")
: new SimpleDateFormat("dd-MMM-yy");
try {
return format.parse(date);
} catch (ParseException e) {
// Log a complaint and include date in the complaint
}
return null;
}
Как уже упоминали другие, если вы можете гарантировать , что вы никогда никогда не получите доступ к DateFormat
в многопоточном режиме, вы можете создавать экземпляры уровня класса или статические экземпляры.
Альтернативой созданию SimpleDateFormat (или двух) на итерацию было бы ленивое заполнение контейнера ThreadLocal для этих форматов. Это решит как проблемы безопасности потоков, так и проблемы, связанные с производительностью создания объектов.