"Own" (the adjective) cannot be used on its own. It should be combined with something like "its own", "our own", "her own", or "the object's own". It also isn't used separately to mean something like "separate". Also, "its own" is correct instead of "it's own" which is a misues of the verb.
318 lines
6.9 KiB
C++
318 lines
6.9 KiB
C++
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup imbuf
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
# include <io.h>
|
|
#endif
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "BLI_fileops.h"
|
|
#include "BLI_path_util.h"
|
|
#include "BLI_utildefines.h"
|
|
#ifdef _WIN32
|
|
# include "BLI_winstuff.h"
|
|
#endif
|
|
|
|
#include "IMB_filetype.hh"
|
|
#include "IMB_imbuf.hh"
|
|
#include "IMB_imbuf_types.hh"
|
|
#include "imbuf.hh"
|
|
|
|
#include "IMB_anim.hh"
|
|
|
|
#ifdef WITH_FFMPEG
|
|
# include "BLI_string.h" /* BLI_vsnprintf */
|
|
|
|
# include "BKE_global.hh" /* G.debug */
|
|
|
|
extern "C" {
|
|
# include <libavcodec/avcodec.h>
|
|
# include <libavdevice/avdevice.h>
|
|
# include <libavformat/avformat.h>
|
|
# include <libavutil/log.h>
|
|
|
|
# include "ffmpeg_compat.h" /* Keep for compatibility. */
|
|
}
|
|
|
|
#endif
|
|
|
|
#define UTIL_DEBUG 0
|
|
|
|
const char *imb_ext_image[] = {
|
|
".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba", ".tif", ".tiff", ".tx",
|
|
#ifdef WITH_OPENJPEG
|
|
".jp2", ".j2c",
|
|
#endif
|
|
".hdr", ".dds",
|
|
#ifdef WITH_CINEON
|
|
".dpx", ".cin",
|
|
#endif
|
|
#ifdef WITH_OPENEXR
|
|
".exr",
|
|
#endif
|
|
".psd", ".pdd", ".psb",
|
|
#ifdef WITH_WEBP
|
|
".webp",
|
|
#endif
|
|
nullptr,
|
|
};
|
|
|
|
const char *imb_ext_movie[] = {
|
|
".avi", ".flc", ".mov", ".movie", ".mp4", ".m4v", ".m2v", ".m2t", ".m2ts", ".mts",
|
|
".ts", ".mv", ".avs", ".wmv", ".ogv", ".ogg", ".r3d", ".dv", ".mpeg", ".mpg",
|
|
".mpg2", ".vob", ".mkv", ".flv", ".divx", ".xvid", ".mxf", ".webm", ".gif", nullptr,
|
|
};
|
|
|
|
/** Sort of wrong having audio extensions in imbuf. */
|
|
|
|
const char *imb_ext_audio[] = {
|
|
".wav",
|
|
".ogg",
|
|
".oga",
|
|
".mp3",
|
|
".mp2",
|
|
".ac3",
|
|
".aac",
|
|
".flac",
|
|
".wma",
|
|
".eac3",
|
|
".aif",
|
|
".aiff",
|
|
".m4a",
|
|
".mka",
|
|
".opus",
|
|
nullptr,
|
|
};
|
|
|
|
/* OIIO will validate the entire header of some files and DPX requires 2048 */
|
|
#define HEADER_SIZE 2048
|
|
|
|
static int64_t imb_ispic_read_header_from_filepath(const char *filepath, uchar buf[HEADER_SIZE])
|
|
{
|
|
BLI_stat_t st;
|
|
int fp;
|
|
|
|
BLI_assert(!BLI_path_is_rel(filepath));
|
|
|
|
if (UTIL_DEBUG) {
|
|
printf("%s: loading %s\n", __func__, filepath);
|
|
}
|
|
|
|
if (BLI_stat(filepath, &st) == -1) {
|
|
return -1;
|
|
}
|
|
if (((st.st_mode) & S_IFMT) != S_IFREG) {
|
|
return -1;
|
|
}
|
|
|
|
if ((fp = BLI_open(filepath, O_BINARY | O_RDONLY, 0)) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
const int64_t size = BLI_read(fp, buf, HEADER_SIZE);
|
|
|
|
close(fp);
|
|
return size;
|
|
}
|
|
|
|
int IMB_ispic_type_from_memory(const uchar *buf, const size_t buf_size)
|
|
{
|
|
for (const ImFileType *type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
|
|
if (type->is_a != nullptr) {
|
|
if (type->is_a(buf, buf_size)) {
|
|
return type->filetype;
|
|
}
|
|
}
|
|
}
|
|
|
|
return IMB_FTYPE_NONE;
|
|
}
|
|
|
|
int IMB_ispic_type(const char *filepath)
|
|
{
|
|
uchar buf[HEADER_SIZE];
|
|
const int64_t buf_size = imb_ispic_read_header_from_filepath(filepath, buf);
|
|
if (buf_size <= 0) {
|
|
return IMB_FTYPE_NONE;
|
|
}
|
|
return IMB_ispic_type_from_memory(buf, size_t(buf_size));
|
|
}
|
|
|
|
bool IMB_ispic_type_matches(const char *filepath, int filetype)
|
|
{
|
|
uchar buf[HEADER_SIZE];
|
|
const int64_t buf_size = imb_ispic_read_header_from_filepath(filepath, buf);
|
|
if (buf_size <= 0) {
|
|
return false;
|
|
}
|
|
|
|
const ImFileType *type = IMB_file_type_from_ftype(filetype);
|
|
if (type != nullptr) {
|
|
/* Requesting to load a type that can't check its own header doesn't make sense.
|
|
* Keep the check for developers. */
|
|
BLI_assert(type->is_a != nullptr);
|
|
if (type->is_a != nullptr) {
|
|
return type->is_a(buf, size_t(buf_size));
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#undef HEADER_SIZE
|
|
|
|
bool IMB_ispic(const char *filepath)
|
|
{
|
|
return (IMB_ispic_type(filepath) != IMB_FTYPE_NONE);
|
|
}
|
|
|
|
#ifdef WITH_FFMPEG
|
|
|
|
/* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */
|
|
# ifdef __GNUC__
|
|
# pragma GCC diagnostic push
|
|
# pragma GCC diagnostic ignored "-Wmissing-format-attribute"
|
|
# endif
|
|
|
|
static char ffmpeg_last_error[1024];
|
|
|
|
static void ffmpeg_log_callback(void *ptr, int level, const char *format, va_list arg)
|
|
{
|
|
if (ELEM(level, AV_LOG_FATAL, AV_LOG_ERROR)) {
|
|
size_t n;
|
|
va_list args_cpy;
|
|
|
|
va_copy(args_cpy, arg);
|
|
n = VSNPRINTF(ffmpeg_last_error, format, args_cpy);
|
|
va_end(args_cpy);
|
|
|
|
/* strip trailing \n */
|
|
ffmpeg_last_error[n - 1] = '\0';
|
|
}
|
|
|
|
if (G.debug & G_DEBUG_FFMPEG) {
|
|
/* call default logger to print all message to console */
|
|
av_log_default_callback(ptr, level, format, arg);
|
|
}
|
|
}
|
|
|
|
# ifdef __GNUC__
|
|
# pragma GCC diagnostic pop
|
|
# endif
|
|
|
|
void IMB_ffmpeg_init()
|
|
{
|
|
avdevice_register_all();
|
|
|
|
ffmpeg_last_error[0] = '\0';
|
|
|
|
if (G.debug & G_DEBUG_FFMPEG) {
|
|
av_log_set_level(AV_LOG_DEBUG);
|
|
}
|
|
|
|
/* set separate callback which could store last error to report to UI */
|
|
av_log_set_callback(ffmpeg_log_callback);
|
|
}
|
|
|
|
const char *IMB_ffmpeg_last_error()
|
|
{
|
|
return ffmpeg_last_error;
|
|
}
|
|
|
|
static int isffmpeg(const char *filepath)
|
|
{
|
|
AVFormatContext *pFormatCtx = nullptr;
|
|
uint i;
|
|
int videoStream;
|
|
const AVCodec *pCodec;
|
|
|
|
if (BLI_path_extension_check_n(filepath,
|
|
".swf",
|
|
".jpg",
|
|
".jp2",
|
|
".j2c",
|
|
".png",
|
|
".dds",
|
|
".tga",
|
|
".bmp",
|
|
".tif",
|
|
".exr",
|
|
".cin",
|
|
".wav",
|
|
nullptr))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (avformat_open_input(&pFormatCtx, filepath, nullptr, nullptr) != 0) {
|
|
if (UTIL_DEBUG) {
|
|
fprintf(stderr, "isffmpeg: av_open_input_file failed\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (avformat_find_stream_info(pFormatCtx, nullptr) < 0) {
|
|
if (UTIL_DEBUG) {
|
|
fprintf(stderr, "isffmpeg: avformat_find_stream_info failed\n");
|
|
}
|
|
avformat_close_input(&pFormatCtx);
|
|
return 0;
|
|
}
|
|
|
|
if (UTIL_DEBUG) {
|
|
av_dump_format(pFormatCtx, 0, filepath, 0);
|
|
}
|
|
|
|
/* Find the first video stream */
|
|
videoStream = -1;
|
|
for (i = 0; i < pFormatCtx->nb_streams; i++) {
|
|
if (pFormatCtx->streams[i] && pFormatCtx->streams[i]->codecpar &&
|
|
(pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO))
|
|
{
|
|
videoStream = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (videoStream == -1) {
|
|
avformat_close_input(&pFormatCtx);
|
|
return 0;
|
|
}
|
|
|
|
AVCodecParameters *codec_par = pFormatCtx->streams[videoStream]->codecpar;
|
|
|
|
/* Find the decoder for the video stream */
|
|
pCodec = avcodec_find_decoder(codec_par->codec_id);
|
|
if (pCodec == nullptr) {
|
|
avformat_close_input(&pFormatCtx);
|
|
return 0;
|
|
}
|
|
|
|
avformat_close_input(&pFormatCtx);
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
bool IMB_isanim(const char *filepath)
|
|
{
|
|
BLI_assert(!BLI_path_is_rel(filepath));
|
|
|
|
if (UTIL_DEBUG) {
|
|
printf("%s: %s\n", __func__, filepath);
|
|
}
|
|
|
|
#ifdef WITH_FFMPEG
|
|
if (isffmpeg(filepath)) {
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|