discard errors when parsing ffprobe output, fixes #530 #546

This commit is contained in:
Taner Sener 2022-08-26 07:39:25 +01:00
parent c82f9c8e74
commit be711ac426
8 changed files with 58 additions and 36 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2021 Taner Sener * Copyright (c) 2018-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -696,7 +696,15 @@ public class FFmpegKitConfig {
final ReturnCode returnCode = new ReturnCode(returnCodeValue); final ReturnCode returnCode = new ReturnCode(returnCodeValue);
mediaInformationSession.complete(returnCode); mediaInformationSession.complete(returnCode);
if (returnCode.isValueSuccess()) { if (returnCode.isValueSuccess()) {
MediaInformation mediaInformation = MediaInformationJsonParser.fromWithError(mediaInformationSession.getAllLogsAsString(waitTimeout)); List<Log> 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); mediaInformationSession.setMediaInformation(mediaInformation);
} }
} catch (final Exception e) { } catch (final Exception e) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Taner Sener * Copyright (c) 2021-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -208,7 +208,7 @@ extern void addSessionToSessionHistory(id<Session> session);
} }
- (void)fail:(NSException*)exception { - (void)fail:(NSException*)exception {
_failStackTrace = [NSString stringWithFormat:@"%@", [exception callStackSymbols]]; _failStackTrace = [NSString stringWithFormat:@"%@\n%@", [exception userInfo], [exception callStackSymbols]];
_state = SessionStateFailed; _state = SessionStateFailed;
_endTime = [NSDate date]; _endTime = [NSDate date];
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2021 Taner Sener * Copyright (c) 2018-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -998,12 +998,20 @@ int executeFFprobe(long sessionId, NSArray* arguments) {
ReturnCode* returnCode = [[ReturnCode alloc] init:returnCodeValue]; ReturnCode* returnCode = [[ReturnCode alloc] init:returnCodeValue];
[mediaInformationSession complete:returnCode]; [mediaInformationSession complete:returnCode];
if ([returnCode isValueSuccess]) { 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]; [mediaInformationSession setMediaInformation:mediaInformation];
} }
} @catch (NSException *exception) { } @catch (NSException *exception) {
[mediaInformationSession fail: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]]);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2021 Taner Sener * Copyright (c) 2018-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -37,13 +37,13 @@
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput; + (MediaInformation*)from:(NSString*)ffprobeJsonOutput;
/** /**
* Extracts <code>MediaInformation</code> from the given FFprobe json output. * Extracts <code>MediaInformation</code> from the given FFprobe json output. If a parsing error occurs an NSException
* is thrown.
* *
* @param ffprobeJsonOutput FFprobe json output * @param ffprobeJsonOutput FFprobe json output
* @param error error to save the parsing error if a parsing error occurs
* @return created MediaInformation instance * @return created MediaInformation instance
*/ */
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput with:(NSError*)error; + (MediaInformation*)fromWithError:(NSString*)ffprobeJsonOutput;
@end @end

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2021 Taner Sener * Copyright (c) 2018-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -25,21 +25,22 @@ NSString* const MediaInformationJsonParserKeyChapters = @"chapters";
@implementation MediaInformationJsonParser @implementation MediaInformationJsonParser
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput { + (MediaInformation*)from:(NSString*)ffprobeJsonOutput {
NSError *error; @try {
return [self fromWithError:ffprobeJsonOutput];
MediaInformation* mediaInformation = [self from: ffprobeJsonOutput with: error]; } @catch (NSException *exception) {
NSLog(@"MediaInformation parsing failed: %@.\n", [NSString stringWithFormat:@"%@\n%@", [exception userInfo], [exception callStackSymbols]]);
if (error != nil) { return nil;
NSLog(@"MediaInformation parsing failed: %@.\n", error);
} }
return mediaInformation;
} }
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput with:(NSError*)error { + (MediaInformation*)fromWithError:(NSString*)ffprobeJsonOutput {
NSError* error = nil;
NSData *jsonData = [ffprobeJsonOutput dataUsingEncoding:NSUTF8StringEncoding]; NSData *jsonData = [ffprobeJsonOutput dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error]; 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; return nil;
} }

View File

@ -42,6 +42,7 @@ extern "C" {
#include <condition_variable> #include <condition_variable>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <algorithm>
/** /**
* Generates ids for named ffmpeg kit pipes. * Generates ids for named ffmpeg kit pipes.
@ -1035,7 +1036,14 @@ void ffmpegkit::FFmpegKitConfig::getMediaInformationExecute(const std::shared_pt
auto returnCode = std::make_shared<ffmpegkit::ReturnCode>(returnCodeValue); auto returnCode = std::make_shared<ffmpegkit::ReturnCode>(returnCodeValue);
mediaInformationSession->complete(returnCode); mediaInformationSession->complete(returnCode);
if (returnCode->isValueSuccess()) { 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<ffmpegkit::Log> log) {
if (log->getLevel() == LevelAVLogStdErr) {
ffprobeJsonOutput.append(log->getMessage());
}
});
auto mediaInformation = ffmpegkit::MediaInformationJsonParser::fromWithError(ffprobeJsonOutput.c_str());
mediaInformationSession->setMediaInformation(mediaInformation); mediaInformationSession->setMediaInformation(mediaInformation);
} }
} catch(const std::exception& exception) { } catch(const std::exception& exception) {

View File

@ -29,24 +29,21 @@ static const char* MediaInformationJsonParserKeyStreams = "streams";
static const char* MediaInformationJsonParserKeyChapters = "chapters"; static const char* MediaInformationJsonParserKeyChapters = "chapters";
std::shared_ptr<ffmpegkit::MediaInformation> ffmpegkit::MediaInformationJsonParser::from(const std::string& ffprobeJsonOutput) { std::shared_ptr<ffmpegkit::MediaInformation> ffmpegkit::MediaInformationJsonParser::from(const std::string& ffprobeJsonOutput) {
std::string error; try {
return fromWithError(ffprobeJsonOutput);
std::shared_ptr<ffmpegkit::MediaInformation> mediaInformation = fromWithError(ffprobeJsonOutput, error); } catch(const std::exception& exception) {
if (mediaInformation == nullptr) { std::cout << "MediaInformation parsing failed: " << exception.what() << std::endl;
std::cout << "MediaInformation parsing failed: " << error << std::endl; return nullptr;
} }
return mediaInformation;
} }
std::shared_ptr<ffmpegkit::MediaInformation> ffmpegkit::MediaInformationJsonParser::fromWithError(const std::string& ffprobeJsonOutput, std::string& error) { std::shared_ptr<ffmpegkit::MediaInformation> ffmpegkit::MediaInformationJsonParser::fromWithError(const std::string& ffprobeJsonOutput) {
std::shared_ptr<rapidjson::Document> document = std::make_shared<rapidjson::Document>(); std::shared_ptr<rapidjson::Document> document = std::make_shared<rapidjson::Document>();
document->Parse(ffprobeJsonOutput.c_str()); document->Parse(ffprobeJsonOutput.c_str());
if (document->HasParseError()) { if (document->HasParseError()) {
error = GetParseError_En(document->GetParseError()); throw std::runtime_error(GetParseError_En(document->GetParseError()));
return nullptr;
} else { } else {
std::shared_ptr<std::vector<std::shared_ptr<ffmpegkit::StreamInformation>>> streams = std::make_shared<std::vector<std::shared_ptr<ffmpegkit::StreamInformation>>>(); std::shared_ptr<std::vector<std::shared_ptr<ffmpegkit::StreamInformation>>> streams = std::make_shared<std::vector<std::shared_ptr<ffmpegkit::StreamInformation>>>();
std::shared_ptr<std::vector<std::shared_ptr<ffmpegkit::Chapter>>> chapters = std::make_shared<std::vector<std::shared_ptr<ffmpegkit::Chapter>>>(); std::shared_ptr<std::vector<std::shared_ptr<ffmpegkit::Chapter>>> chapters = std::make_shared<std::vector<std::shared_ptr<ffmpegkit::Chapter>>>();

View File

@ -40,13 +40,13 @@ namespace ffmpegkit {
static std::shared_ptr<ffmpegkit::MediaInformation> from(const std::string& ffprobeJsonOutput); static std::shared_ptr<ffmpegkit::MediaInformation> from(const std::string& ffprobeJsonOutput);
/** /**
* Extracts <code>MediaInformation</code> from the given FFprobe json output. * Extracts <code>MediaInformation</code> from the given FFprobe json output. If a parsing error occurs an
* std::exception is thrown.
* *
* @param ffprobeJsonOutput FFprobe json output * @param ffprobeJsonOutput FFprobe json output
* @param error error to save the parsing error if a parsing error occurs
* @return created MediaInformation instance * @return created MediaInformation instance
*/ */
static std::shared_ptr<ffmpegkit::MediaInformation> fromWithError(const std::string& ffprobeJsonOutput, std::string& error); static std::shared_ptr<ffmpegkit::MediaInformation> fromWithError(const std::string& ffprobeJsonOutput);
}; };