From be711ac426a606782f45dd1874cd54104c13afcc Mon Sep 17 00:00:00 2001 From: Taner Sener Date: Fri, 26 Aug 2022 07:39:25 +0100 Subject: [PATCH] discard errors when parsing ffprobe output, fixes #530 #546 --- .../arthenica/ffmpegkit/FFmpegKitConfig.java | 12 ++++++++-- apple/src/AbstractSession.m | 4 ++-- apple/src/FFmpegKitConfig.m | 14 ++++++++--- apple/src/MediaInformationJsonParser.h | 8 +++---- apple/src/MediaInformationJsonParser.m | 23 ++++++++++--------- linux/src/FFmpegKitConfig.cpp | 10 +++++++- linux/src/MediaInformationJsonParser.cpp | 17 ++++++-------- linux/src/MediaInformationJsonParser.h | 6 ++--- 8 files changed, 58 insertions(+), 36 deletions(-) diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java index 3f82cc3..4c63abd 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Taner Sener + * Copyright (c) 2018-2022 Taner Sener * * This file is part of FFmpegKit. * @@ -696,7 +696,15 @@ public class FFmpegKitConfig { final ReturnCode returnCode = new ReturnCode(returnCodeValue); mediaInformationSession.complete(returnCode); if (returnCode.isValueSuccess()) { - MediaInformation mediaInformation = MediaInformationJsonParser.fromWithError(mediaInformationSession.getAllLogsAsString(waitTimeout)); + List allLogs = mediaInformationSession.getAllLogs(waitTimeout); + final StringBuilder ffprobeJsonOutput = new StringBuilder(); + for (int i = 0, allLogsSize = allLogs.size(); i < allLogsSize; i++) { + Log log = allLogs.get(i); + if (log.getLevel() == Level.AV_LOG_STDERR) { + ffprobeJsonOutput.append(log.getMessage()); + } + } + MediaInformation mediaInformation = MediaInformationJsonParser.fromWithError(ffprobeJsonOutput.toString()); mediaInformationSession.setMediaInformation(mediaInformation); } } catch (final Exception e) { diff --git a/apple/src/AbstractSession.m b/apple/src/AbstractSession.m index f2e40ac..e9f87e9 100644 --- a/apple/src/AbstractSession.m +++ b/apple/src/AbstractSession.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Taner Sener + * Copyright (c) 2021-2022 Taner Sener * * This file is part of FFmpegKit. * @@ -208,7 +208,7 @@ extern void addSessionToSessionHistory(id session); } - (void)fail:(NSException*)exception { - _failStackTrace = [NSString stringWithFormat:@"%@", [exception callStackSymbols]]; + _failStackTrace = [NSString stringWithFormat:@"%@\n%@", [exception userInfo], [exception callStackSymbols]]; _state = SessionStateFailed; _endTime = [NSDate date]; } diff --git a/apple/src/FFmpegKitConfig.m b/apple/src/FFmpegKitConfig.m index 3194471..ab3b390 100644 --- a/apple/src/FFmpegKitConfig.m +++ b/apple/src/FFmpegKitConfig.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Taner Sener + * Copyright (c) 2018-2022 Taner Sener * * This file is part of FFmpegKit. * @@ -998,12 +998,20 @@ int executeFFprobe(long sessionId, NSArray* arguments) { ReturnCode* returnCode = [[ReturnCode alloc] init:returnCodeValue]; [mediaInformationSession complete:returnCode]; if ([returnCode isValueSuccess]) { - MediaInformation* mediaInformation = [MediaInformationJsonParser from:[mediaInformationSession getAllLogsAsStringWithTimeout:waitTimeout]]; + NSArray* allLogs = [mediaInformationSession getAllLogsWithTimeout:waitTimeout]; + NSMutableString* ffprobeJsonOutput = [[NSMutableString alloc] init]; + for (int i=0; i < [allLogs count]; i++) { + Log* log = [allLogs objectAtIndex:i]; + if ([log getLevel] == LevelAVLogStdErr) { + [ffprobeJsonOutput appendString:[log getMessage]]; + } + } + MediaInformation* mediaInformation = [MediaInformationJsonParser fromWithError:ffprobeJsonOutput]; [mediaInformationSession setMediaInformation:mediaInformation]; } } @catch (NSException *exception) { [mediaInformationSession fail:exception]; - NSLog(@"Get media information execute failed: %@.%@", [FFmpegKitConfig argumentsToString:[mediaInformationSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]); + NSLog(@"Get media information execute failed: %@.%@", [FFmpegKitConfig argumentsToString:[mediaInformationSession getArguments]], [NSString stringWithFormat:@"\n%@\n%@", [exception userInfo], [exception callStackSymbols]]); } } diff --git a/apple/src/MediaInformationJsonParser.h b/apple/src/MediaInformationJsonParser.h index 91f3db8..b78c2cb 100644 --- a/apple/src/MediaInformationJsonParser.h +++ b/apple/src/MediaInformationJsonParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Taner Sener + * Copyright (c) 2018-2022 Taner Sener * * This file is part of FFmpegKit. * @@ -37,13 +37,13 @@ + (MediaInformation*)from:(NSString*)ffprobeJsonOutput; /** - * Extracts MediaInformation from the given FFprobe json output. + * Extracts MediaInformation from the given FFprobe json output. If a parsing error occurs an NSException + * is thrown. * * @param ffprobeJsonOutput FFprobe json output - * @param error error to save the parsing error if a parsing error occurs * @return created MediaInformation instance */ -+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput with:(NSError*)error; ++ (MediaInformation*)fromWithError:(NSString*)ffprobeJsonOutput; @end diff --git a/apple/src/MediaInformationJsonParser.m b/apple/src/MediaInformationJsonParser.m index c7fe7cb..7d35f39 100644 --- a/apple/src/MediaInformationJsonParser.m +++ b/apple/src/MediaInformationJsonParser.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Taner Sener + * Copyright (c) 2018-2022 Taner Sener * * This file is part of FFmpegKit. * @@ -25,21 +25,22 @@ NSString* const MediaInformationJsonParserKeyChapters = @"chapters"; @implementation MediaInformationJsonParser + (MediaInformation*)from:(NSString*)ffprobeJsonOutput { - NSError *error; - - MediaInformation* mediaInformation = [self from: ffprobeJsonOutput with: error]; - - if (error != nil) { - NSLog(@"MediaInformation parsing failed: %@.\n", error); + @try { + return [self fromWithError:ffprobeJsonOutput]; + } @catch (NSException *exception) { + NSLog(@"MediaInformation parsing failed: %@.\n", [NSString stringWithFormat:@"%@\n%@", [exception userInfo], [exception callStackSymbols]]); + return nil; } - - return mediaInformation; } -+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput with:(NSError*)error { ++ (MediaInformation*)fromWithError:(NSString*)ffprobeJsonOutput { + NSError* error = nil; NSData *jsonData = [ffprobeJsonOutput dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error]; - if (error != nil || jsonDictionary == nil) { + if (error != nil) { + @throw [NSException exceptionWithName:@"ParsingException" reason:[NSString stringWithFormat:@"%ld",[error code]] userInfo:[error userInfo]]; + } + if (jsonDictionary == nil) { return nil; } diff --git a/linux/src/FFmpegKitConfig.cpp b/linux/src/FFmpegKitConfig.cpp index 300b9ea..c8e61fc 100644 --- a/linux/src/FFmpegKitConfig.cpp +++ b/linux/src/FFmpegKitConfig.cpp @@ -42,6 +42,7 @@ extern "C" { #include #include #include +#include /** * Generates ids for named ffmpeg kit pipes. @@ -1035,7 +1036,14 @@ void ffmpegkit::FFmpegKitConfig::getMediaInformationExecute(const std::shared_pt auto returnCode = std::make_shared(returnCodeValue); mediaInformationSession->complete(returnCode); if (returnCode->isValueSuccess()) { - auto mediaInformation = ffmpegkit::MediaInformationJsonParser::from(mediaInformationSession->getAllLogsAsStringWithTimeout(waitTimeout).c_str()); + auto allLogs = mediaInformationSession->getAllLogsWithTimeout(waitTimeout); + std::string ffprobeJsonOutput; + std::for_each(allLogs->cbegin(), allLogs->cend(), [&](std::shared_ptr log) { + if (log->getLevel() == LevelAVLogStdErr) { + ffprobeJsonOutput.append(log->getMessage()); + } + }); + auto mediaInformation = ffmpegkit::MediaInformationJsonParser::fromWithError(ffprobeJsonOutput.c_str()); mediaInformationSession->setMediaInformation(mediaInformation); } } catch(const std::exception& exception) { diff --git a/linux/src/MediaInformationJsonParser.cpp b/linux/src/MediaInformationJsonParser.cpp index 99908a9..819e7e3 100644 --- a/linux/src/MediaInformationJsonParser.cpp +++ b/linux/src/MediaInformationJsonParser.cpp @@ -29,24 +29,21 @@ static const char* MediaInformationJsonParserKeyStreams = "streams"; static const char* MediaInformationJsonParserKeyChapters = "chapters"; std::shared_ptr ffmpegkit::MediaInformationJsonParser::from(const std::string& ffprobeJsonOutput) { - std::string error; - - std::shared_ptr mediaInformation = fromWithError(ffprobeJsonOutput, error); - if (mediaInformation == nullptr) { - std::cout << "MediaInformation parsing failed: " << error << std::endl; + try { + return fromWithError(ffprobeJsonOutput); + } catch(const std::exception& exception) { + std::cout << "MediaInformation parsing failed: " << exception.what() << std::endl; + return nullptr; } - - return mediaInformation; } -std::shared_ptr ffmpegkit::MediaInformationJsonParser::fromWithError(const std::string& ffprobeJsonOutput, std::string& error) { +std::shared_ptr ffmpegkit::MediaInformationJsonParser::fromWithError(const std::string& ffprobeJsonOutput) { std::shared_ptr document = std::make_shared(); document->Parse(ffprobeJsonOutput.c_str()); if (document->HasParseError()) { - error = GetParseError_En(document->GetParseError()); - return nullptr; + throw std::runtime_error(GetParseError_En(document->GetParseError())); } else { std::shared_ptr>> streams = std::make_shared>>(); std::shared_ptr>> chapters = std::make_shared>>(); diff --git a/linux/src/MediaInformationJsonParser.h b/linux/src/MediaInformationJsonParser.h index d07cab9..0ff4d01 100644 --- a/linux/src/MediaInformationJsonParser.h +++ b/linux/src/MediaInformationJsonParser.h @@ -40,13 +40,13 @@ namespace ffmpegkit { static std::shared_ptr from(const std::string& ffprobeJsonOutput); /** - * Extracts MediaInformation from the given FFprobe json output. + * Extracts MediaInformation from the given FFprobe json output. If a parsing error occurs an + * std::exception is thrown. * * @param ffprobeJsonOutput FFprobe json output - * @param error error to save the parsing error if a parsing error occurs * @return created MediaInformation instance */ - static std::shared_ptr fromWithError(const std::string& ffprobeJsonOutput, std::string& error); + static std::shared_ptr fromWithError(const std::string& ffprobeJsonOutput); };