aboutsummaryrefslogtreecommitdiff
path: root/src/FileAnalyzer.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-02-16 21:54:47 +0100
committerdec05eba <dec05eba@protonmail.com>2022-02-17 19:18:34 +0100
commitd4cd63129ae5dff8fd69525424e0f8cb9ae1a905 (patch)
tree957c957f0ca1796105318b7595545dcfc7e04af7 /src/FileAnalyzer.cpp
parent5061e1ad912bccf89df25258e7dd8b386b0a7239 (diff)
Wip: fix video duration not working for some analyzed files, get frame in middle of video instead of first frame for thumbnail
Diffstat (limited to 'src/FileAnalyzer.cpp')
-rw-r--r--src/FileAnalyzer.cpp64
1 files changed, 39 insertions, 25 deletions
diff --git a/src/FileAnalyzer.cpp b/src/FileAnalyzer.cpp
index 6f1c1ee..4e4470e 100644
--- a/src/FileAnalyzer.cpp
+++ b/src/FileAnalyzer.cpp
@@ -21,7 +21,7 @@ namespace QuickMedia {
// https://mimesniff.spec.whatwg.org/
// TODO: Test all of these
- static const std::array<MagicNumber, 30> magic_numbers = {
+ static const std::array<MagicNumber, 31> magic_numbers = {
MagicNumber{ {'R', 'I', 'F', 'F', -1, -1, -1, -1, 'A', 'V', 'I', ' '}, 12, ContentType::VIDEO_AVI },
MagicNumber{ {0x00, 0x00, 0x00, -1, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm'}, 12, ContentType::VIDEO_MP4 },
MagicNumber{ {0x00, 0x00, 0x00, -1, 'f', 't', 'y', 'p', 'm', 'p', '4', '2'}, 12, ContentType::VIDEO_MP4 },
@@ -34,6 +34,7 @@ namespace QuickMedia {
MagicNumber{ {0x00, 0x00, 0x01, 0xB3}, 4, ContentType::VIDEO_MPEG },
MagicNumber{ {0x1A, 0x45, 0xDF, 0xA3}, 4, ContentType::VIDEO_WEBM },
MagicNumber{ {'F', 'L', 'V', 0x01}, 4, ContentType::VIDEO_FLV },
+ MagicNumber{ {0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF}, 7, ContentType::VIDEO_WMV },
MagicNumber{ {'.', 's', 'n', 'd'}, 4, ContentType::AUDIO_BASIC },
MagicNumber{ {'F', 'O', 'R', 'M', -1, -1, -1, -1, 'A', 'I', 'F', 'F'}, 12, ContentType::AUDIO_AIFF },
MagicNumber{ { 'I', 'D', '3' }, 3, ContentType::AUDIO_MPEG },
@@ -56,7 +57,7 @@ namespace QuickMedia {
};
bool is_content_type_video(ContentType content_type) {
- return content_type >= ContentType::VIDEO_AVI && content_type <= ContentType::VIDEO_FLV;
+ return content_type >= ContentType::VIDEO_AVI && content_type <= ContentType::VIDEO_WMV;
}
bool is_content_type_audio(ContentType content_type) {
@@ -75,6 +76,7 @@ namespace QuickMedia {
case ContentType::VIDEO_MPEG: return "video/mpeg";
case ContentType::VIDEO_WEBM: return "video/webm";
case ContentType::VIDEO_FLV: return "video/x-flv";
+ case ContentType::VIDEO_WMV: return "video/x-ms-asf";
case ContentType::AUDIO_BASIC: return "audio/basic";
case ContentType::AUDIO_AIFF: return "audio/aiff";
case ContentType::AUDIO_MPEG: return "audio/mpeg";
@@ -106,6 +108,7 @@ namespace QuickMedia {
|| strcase_equals(ext, ".flv")
|| strcase_equals(ext, ".vob")
|| strcase_equals(ext, ".ogv")
+ || strcase_equals(ext, ".ogg")
|| strcase_equals(ext, ".avi")
//|| strcase_equals(ext, ".ts")
|| strcase_equals(ext, ".mov")
@@ -124,30 +127,37 @@ namespace QuickMedia {
return 0;
}
- bool video_get_first_frame(const char *filepath, const char *destination_path, int width, int height) {
+ bool video_get_first_frame(const FileAnalyzer &file, const char *destination_path, int width, int height) {
Path destination_path_tmp = destination_path;
destination_path_tmp.append(".ftmp");
- const char *program_args[] = { "ffmpeg", "-y", "-v", "quiet", "-i", filepath, "-vframes", "1", "-f", "singlejpeg", "--", destination_path_tmp.data.c_str(), nullptr };
- std::string ffmpeg_result;
- if(exec_program(program_args, nullptr, nullptr) != 0) {
- fprintf(stderr, "Failed to execute ffmpeg, maybe its not installed?\n");
- return false;
- }
+ const int middle_seconds = file.get_duration_seconds().value_or(0.0) / 2.0;
+ char middle_seconds_str[32];
+ snprintf(middle_seconds_str, sizeof(middle_seconds_str), "%d", middle_seconds);
if(width > 0 && height > 0) {
- FileAnalyzer file_analyzer;
- const bool success = file_analyzer.load_file(destination_path_tmp.data.c_str(), false) && create_thumbnail(destination_path_tmp, destination_path, mgl::vec2i(width, height), file_analyzer.get_content_type(), false);
- remove(destination_path_tmp.data.c_str());
- return success;
+ char framesize[128];
+ snprintf(framesize, sizeof(framesize), "%dx%d", width, height);
+
+ const char *program_args[] = { "ffmpeg", "-y", "-v", "quiet", "-ss", middle_seconds_str, "-i", file.get_filepath().c_str(), "-vframes", "1", "-f", "singlejpeg", "-s", framesize, "--", destination_path_tmp.data.c_str(), nullptr };
+ if(exec_program(program_args, nullptr, nullptr) != 0) {
+ fprintf(stderr, "Failed to execute ffmpeg, maybe its not installed?\n");
+ return false;
+ }
} else {
- return rename_atomic(destination_path_tmp.data.c_str(), destination_path) == 0;
+ const char *program_args[] = { "ffmpeg", "-y", "-v", "quiet", "-ss", middle_seconds_str, "-i", file.get_filepath().c_str(), "-vframes", "1", "-f", "singlejpeg", "--", destination_path_tmp.data.c_str(), nullptr };
+ if(exec_program(program_args, nullptr, nullptr) != 0) {
+ fprintf(stderr, "Failed to execute ffmpeg, maybe its not installed?\n");
+ return false;
+ }
}
+
+ return rename_atomic(destination_path_tmp.data.c_str(), destination_path) == 0;
}
// TODO: Remove dependency on ffprobe
static bool ffprobe_extract_metadata(const char *filepath, std::optional<Dimensions> &dimensions, std::optional<double> &duration_seconds) {
- const char *program_args[] = { "ffprobe", "-v", "quiet", "-print_format", "json", "-show_streams", "--", filepath, nullptr };
+ const char *program_args[] = { "ffprobe", "-v", "quiet", "-print_format", "json", "-show_streams", "-show_format", "--", filepath, nullptr };
std::string ffprobe_result;
if(exec_program(program_args, accumulate_string, &ffprobe_result) != 0) {
fprintf(stderr, "Failed to execute ffprobe, maybe its not installed?\n");
@@ -181,20 +191,19 @@ namespace QuickMedia {
if(strcmp(codec_type.asCString(), "video") == 0) {
const Json::Value &width_json = stream_json["width"];
const Json::Value &height_json = stream_json["height"];
- const Json::Value &duration_json = stream_json["duration"];
if(width_json.isNumeric() && height_json.isNumeric())
dimensions = { width_json.asInt(), height_json.asInt() };
- if(duration_json.isString())
- duration_seconds = atof(duration_json.asCString());
- break;
- } else if(strcmp(codec_type.asCString(), "audio") == 0) {
- const Json::Value &duration_json = stream_json["duration"];
- if(duration_json.isString())
- duration_seconds = atof(duration_json.asCString());
- // No break here because if there is video after this, we want it to overwrite this
}
}
+ const Json::Value &format_json = json_root["format"];
+ if(!format_json.isObject())
+ return true;
+
+ const Json::Value &duration_json = format_json["duration"];
+ if(duration_json.isString())
+ duration_seconds = atof(duration_json.asCString());
+
return true;
}
@@ -231,7 +240,7 @@ namespace QuickMedia {
unsigned char magic_number_buffer[MAGIC_NUMBER_BUFFER_SIZE];
size_t num_bytes_read = fread(magic_number_buffer, 1, sizeof(magic_number_buffer), file);
- if(feof(file)) {
+ if(feof(file) || num_bytes_read != sizeof(magic_number_buffer)) {
perror(filepath);
fclose(file);
return false;
@@ -263,10 +272,15 @@ namespace QuickMedia {
duration_seconds = std::nullopt;
}
+ this->filepath = filepath;
loaded = true;
return true;
}
+ const std::string& FileAnalyzer::get_filepath() const {
+ return filepath;
+ }
+
ContentType FileAnalyzer::get_content_type() const {
return content_type;
}