/*! * COPYRIGHT (C) 2020 Emeric Grange - All Rights Reserved * * This file is part of MiniVideo. * * MiniVideo 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. * * MiniVideo 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 MiniVideo. If not, see . * * \author Emeric Grange * \date 2010 */ // minivideo headers #include "import.h" #include "minitraces.h" #include "minivideo_typedef.h" #include "minivideo_containers.h" // minivideo headers #include "minivideo_mediafile.h" // C standard libraries #include #include #include #include // C POSIX library #ifdef _MSC_VER #include #define getcwd _getcwd #else #include #endif /* ************************************************************************** */ /*! * \brief Get various from a media filepath. * \param[in] *media: A pointer to a MediaFile_t structure, containing every informations available about the current media file. * * Get absolute file path, file directory, file name and extension. * This function will only work with Unix-style file systems. */ static void getInfosFromPath(MediaFile_t *media) { TRACE_2(IO, "getInfosFromPath()"); // Check if mediaFile->filepath is an absolute path char *pos_first_slash_p = strchr(media->file_path, '/'); if ((pos_first_slash_p != NULL) && ((pos_first_slash_p - media->file_path) == 0)) { TRACE_2(IO, "* mediaFile->file_path seems to be an absolute path already (first caracter is /)"); } else { char cwd[4096]; char absolute_filepath[4096]; FILE *temp = NULL; // First attempt if (getcwd(cwd, sizeof(cwd)) != NULL) { strncpy(absolute_filepath, strncat(cwd, media->file_path, sizeof(cwd) - 1), sizeof(absolute_filepath) - 1); temp = fopen(absolute_filepath, "rb"); } if (temp != NULL) { TRACE_2(IO, "* New absolute file path found, new using method 1: '%s'", absolute_filepath); strncpy(media->file_path, absolute_filepath, sizeof(media->file_path) - 1); fclose(temp); } else { // Second attempt if (getcwd(cwd, sizeof(cwd)) != NULL) { strncpy(absolute_filepath, strncat(cwd, "/", 1), sizeof(absolute_filepath) - 1); strncat(absolute_filepath, media->file_path, sizeof(absolute_filepath) - 1); temp = fopen(absolute_filepath, "rb"); } if (temp != NULL) { TRACE_2(IO, "* New absolute file path found, new using method 2"); strncpy(media->file_path, absolute_filepath, sizeof(media->file_path) - 1); fclose(temp); } else { TRACE_2(IO, "* mediaFile->file_path seems to be an absolute path already"); } } } // Get directory char *pos_last_slash_p = strrchr(media->file_path, '/'); if (pos_last_slash_p != NULL) { unsigned int pos_last_slash_i = pos_last_slash_p - media->file_path + 1; if (pos_last_slash_i > sizeof(media->file_directory) - 1) { pos_last_slash_i = sizeof(media->file_directory) - 1; } // Set directory strncpy(media->file_directory, media->file_path, pos_last_slash_i); // Get file name char *pos_last_dot_p = strrchr(media->file_path, '.'); if (pos_last_dot_p != NULL) { unsigned int pos_last_dot_i = pos_last_dot_p - media->file_path - pos_last_slash_i; if (pos_last_dot_i > sizeof(media->file_name) - 1) { pos_last_dot_i = sizeof(media->file_name) - 1; } // Set file name strncpy(media->file_name, pos_last_slash_p + 1, pos_last_dot_i); // Set file extension (without the dot) strncpy(media->file_extension, pos_last_dot_p + 1, sizeof(media->file_extension) - 1); } else { TRACE_WARNING(IO, "* Cannot find file extension!"); // Set file name (without the extension) strncpy(media->file_name, pos_last_slash_p + 1, 254); } } else { TRACE_WARNING(IO, "* Cannot find file directory, name and extension!"); } // Print results TRACE_1(IO, "* File path : '%s'", media->file_path); TRACE_1(IO, "* File directory : '%s'", media->file_directory); TRACE_1(IO, "* File name : '%s'", media->file_name); TRACE_1(IO, "* File extension : '%s'", media->file_extension); } /* ************************************************************************** */ /*! * \brief Get media file size. * \param[in] *media: A pointer to a MediaFile_t structure containing various informations about the file. */ static void getSize(MediaFile_t *media) { TRACE_2(IO, "getSize()"); fseek(media->file_pointer, 0, SEEK_END); media->file_size = (int64_t)ftell(media->file_pointer); rewind(media->file_pointer); if (media->file_size < 1024) // < 1 KiB { TRACE_1(IO, "* File size : %i bytes", media->file_size); } else if (media->file_size < 1048576) // < 1 MiB { TRACE_1(IO, "* File size : %.2f KiB (%.2f KB)", (double)media->file_size / 1024.0, (double)media->file_size / 1000.0); } else // >= 1 MiB { TRACE_1(IO, "* File size : %.2f MiB (%.2f MB)", (double)media->file_size / 1024.0 / 1024.0, (double)media->file_size / 1000.0 / 1000.0); } } /* ************************************************************************** */ /*! * \brief Detect the container used by a multimedia file. * \param[in] *media: A pointer to a MediaFile_t structure, containing every informations available about the current media file. */ static void getContainer(MediaFile_t *media) { media->container = CONTAINER_UNKNOWN; // Detect container format using start codes, by readind the first bytes of the file rewind(media->file_pointer); uint8_t buffer[16]; if (fread(buffer, sizeof(uint8_t), sizeof(buffer), media->file_pointer) == sizeof(buffer)) { media->container = getContainerUsingStartcodes(buffer); } if (media->container == CONTAINER_UNKNOWN) { TRACE_WARNING(IO, "* Unknown container format: startcodes detection failed..."); // Fallback: detect container format using file extension std::string ext = media->file_extension; media->container = getContainerUsingExtension(ext); if (media->container == CONTAINER_UNKNOWN) { TRACE_ERROR(IO, "* Unknown container format: file extension detection failed..."); } } } /* ************************************************************************** */ /* ************************************************************************** */ /*! * \brief Open a file and check what's inside it. * \param[in] *filepath: The path of the file to load. * \param[in,out] **media_ptr: A pointer to a MediaFile_t structure, containing every informations available about the current media file. * * Some more informations about supported files: * Size and offset are coded on int64_t (signed long long), so this library should * be able to handle file of 1073741824 GiB if Large File Support is enabled during * compilation, 2 GiB otherwise. * The filename is limited to 255 caracters (including file extension) and the * complete filepath is limited to 4096 caracters. * * These parameters will only work on POSIX compliant operating system. */ int import_fileOpen(const char *filepath, MediaFile_t **media_ptr) { TRACE_INFO(IO, BLD_GREEN "import_fileOpen()" CLR_RESET); int retcode = FAILURE; if (filepath == NULL) { TRACE_ERROR(IO, "* File path is invalid"); } else { // Allocate media structure and create a shortcut *media_ptr = (MediaFile_t*)calloc(1, sizeof(MediaFile_t)); if (*media_ptr == NULL) { TRACE_ERROR(IO, "* Unable to allocate a MediaFile_t structure!"); } else { MediaFile_t *media = (*media_ptr); // Set filepath in MediaFile_t strncpy(media->file_path, filepath, sizeof(media->file_path) - 1); TRACE_INFO(IO, "* File path (raw): '%s'", filepath); // Open file, read only media->file_pointer = fopen(filepath, "rb"); if (media->file_pointer == NULL) { TRACE_ERROR(IO, "Unable to open the media file: '%s'!", filepath); free(*media_ptr); *media_ptr = NULL; } else { TRACE_1(IO, "* File successfully opened"); // Extract some informations from the media file getInfosFromPath(media); getSize(media); getContainer(media); retcode = SUCCESS; } } } return retcode; } /* ************************************************************************** */ /*! * \brief Close a file. * \param[in,out] **media_ptr: A pointer of pointer to a MediaFile_t structure. * \return 1 if success, 0 otherwise. */ int import_fileClose(MediaFile_t **media_ptr) { TRACE_INFO(IO, BLD_GREEN "import_fileClose()" CLR_RESET); int retcode = SUCCESS; int i = 0; if ((*media_ptr) != NULL) { if ((*media_ptr)->file_pointer != NULL) { if (fclose((*media_ptr)->file_pointer) == 0) { TRACE_1(IO, "* File successfully closed"); retcode = SUCCESS; } else { TRACE_ERROR(IO, "Unable to close that file!"); retcode = FAILURE; } } { free(*media_ptr); *media_ptr = NULL; TRACE_1(IO, ">> MediaFile freed"); } } return retcode; } /* ************************************************************************** */ /*! * \brief Print various informations about a file. * \param[in] *media: A pointer to a MediaFile_t structure, containing every informations available about the current media file. */ void import_fileStatus(MediaFile_t *media) { TRACE_INFO(IO, BLD_GREEN "import_fileStatus()" CLR_RESET); unsigned i = 0; // File if (media->file_pointer) { TRACE_1(IO, "file_pointer is " BLD_GREEN "open" CLR_RESET); } else { TRACE_1(IO, "file_pointer is " BLD_RED "closed" CLR_RESET); } // File info TRACE_1(IO, "* File path : '%s'", media->file_path); TRACE_1(IO, "* File directory : '%s'", media->file_directory); TRACE_1(IO, "* File name : '%s'", media->file_name); TRACE_1(IO, "* File extension : '%s'", media->file_extension); TRACE_1(IO, "* File size : %i MiB / %i MB", media->file_size / 1024 / 1024, media->file_size / 1000 / 1000); // File format TRACE_1(IO, "* File container : '%s'", getContainerString(media->container, 1)); } /* ************************************************************************** */