This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/imbuf/intern/util.c
Philipp Oeser c5db0272d4 Fix T70276: View animation with jpeg 2000 image will crash player
Since our ffmpeg is built with openjpeg support and thus can decode jpeg
2000 (in both J2K and JP2 codec flavors as well as high bitdepths), added
these extensions to the supported list.

Also IMB_ispic > IMB_ispic_type > imb_is_a_jp2 was only testing for jp2,
now do both jp2/j2k.

Reviewers: brecht

Maniphest Tasks: T70276

Differential Revision: https://developer.blender.org/D5909
2019-09-27 12:02:08 +02:00

405 lines
8.3 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
* util.c
*/
/** \file
* \ingroup imbuf
*/
#ifdef _WIN32
# include <io.h>
#endif
#include <stdlib.h>
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
#include "BLI_fileops.h"
#include "imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_filetype.h"
#include "IMB_anim.h"
#ifdef WITH_FFMPEG
# include "BLI_string.h" /* BLI_vsnprintf */
# include "BKE_global.h" /* G.debug */
# include <libavcodec/avcodec.h>
# include <libavformat/avformat.h>
# include <libavdevice/avdevice.h>
# include <libavutil/log.h>
# include "ffmpeg_compat.h"
#endif
#define UTIL_DEBUG 0
const char *imb_ext_image[] = {
".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba",
#ifdef WITH_TIFF
".tif", ".tiff", ".tx",
#endif
#ifdef WITH_OPENJPEG
".jp2", ".j2c",
#endif
#ifdef WITH_HDR
".hdr",
#endif
#ifdef WITH_DDS
".dds",
#endif
#ifdef WITH_CINEON
".dpx", ".cin",
#endif
#ifdef WITH_OPENEXR
".exr",
#endif
#ifdef WITH_OPENIMAGEIO
".psd", ".pdd", ".psb",
#endif
NULL,
};
const char *imb_ext_image_filepath_only[] = {
#ifdef WITH_OPENIMAGEIO
".psd",
".pdd",
".psb",
#endif
NULL,
};
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", NULL,
};
/* sort of wrong being here... */
const char *imb_ext_audio[] = {
".wav",
".ogg",
".oga",
".mp3",
".mp2",
".ac3",
".aac",
".flac",
".wma",
".eac3",
".aif",
".aiff",
".m4a",
".mka",
NULL,
};
int IMB_ispic_type(const char *name)
{
/* increased from 32 to 64 because of the bitmaps header size */
#define HEADER_SIZE 64
unsigned char buf[HEADER_SIZE];
const ImFileType *type;
BLI_stat_t st;
int fp;
BLI_assert(!BLI_path_is_rel(name));
if (UTIL_DEBUG) {
printf("%s: loading %s\n", __func__, name);
}
if (BLI_stat(name, &st) == -1) {
return false;
}
if (((st.st_mode) & S_IFMT) != S_IFREG) {
return false;
}
if ((fp = BLI_open(name, O_BINARY | O_RDONLY, 0)) == -1) {
return false;
}
memset(buf, 0, sizeof(buf));
if (read(fp, buf, HEADER_SIZE) <= 0) {
close(fp);
return false;
}
close(fp);
/* XXX move this exception */
if ((BIG_LONG(((int *)buf)[0]) & 0xfffffff0) == 0xffd8ffe0) {
return IMB_FTYPE_JPG;
}
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->is_a) {
if (type->is_a(buf)) {
return type->filetype;
}
}
else if (type->is_a_filepath) {
if (type->is_a_filepath(name)) {
return type->filetype;
}
}
}
return 0;
#undef HEADER_SIZE
}
bool IMB_ispic(const char *name)
{
return (IMB_ispic_type(name) != 0);
}
static int isavi(const char *name)
{
#ifdef WITH_AVI
return AVI_is_avi(name);
#else
(void)name;
return false;
#endif
}
#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 = BLI_vsnprintf(ffmpeg_last_error, sizeof(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(void)
{
av_register_all();
avdevice_register_all();
ffmpeg_last_error[0] = '\0';
if (G.debug & G_DEBUG_FFMPEG) {
av_log_set_level(AV_LOG_DEBUG);
}
/* set own callback which could store last error to report to UI */
av_log_set_callback(ffmpeg_log_callback);
}
const char *IMB_ffmpeg_last_error(void)
{
return ffmpeg_last_error;
}
static int isffmpeg(const char *filename)
{
AVFormatContext *pFormatCtx = NULL;
unsigned int i;
int videoStream;
AVCodec *pCodec;
AVCodecContext *pCodecCtx;
if (BLI_path_extension_check_n(filename,
".swf",
".jpg",
".jp2",
".j2c",
".png",
".dds",
".tga",
".bmp",
".tif",
".exr",
".cin",
".wav",
NULL)) {
return 0;
}
if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) {
if (UTIL_DEBUG) {
fprintf(stderr, "isffmpeg: av_open_input_file failed\n");
}
return 0;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 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, filename, 0);
}
/* Find the first video stream */
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i] && pFormatCtx->streams[i]->codec &&
(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)) {
videoStream = i;
break;
}
}
if (videoStream == -1) {
avformat_close_input(&pFormatCtx);
return 0;
}
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
/* Find the decoder for the video stream */
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
avformat_close_input(&pFormatCtx);
return 0;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
avformat_close_input(&pFormatCtx);
return 0;
}
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 1;
}
#endif
int imb_get_anim_type(const char *name)
{
int type;
BLI_stat_t st;
BLI_assert(!BLI_path_is_rel(name));
if (UTIL_DEBUG) {
printf("%s: %s\n", __func__, name);
}
#ifndef _WIN32
# ifdef WITH_FFMPEG
/* stat test below fails on large files > 4GB */
if (isffmpeg(name)) {
return (ANIM_FFMPEG);
}
# endif
if (BLI_stat(name, &st) == -1) {
return (0);
}
if (((st.st_mode) & S_IFMT) != S_IFREG) {
return (0);
}
if (isavi(name)) {
return (ANIM_AVI);
}
if (ismovie(name)) {
return (ANIM_MOVIE);
}
#else
if (BLI_stat(name, &st) == -1) {
return (0);
}
if (((st.st_mode) & S_IFMT) != S_IFREG) {
return (0);
}
if (ismovie(name)) {
return (ANIM_MOVIE);
}
# ifdef WITH_FFMPEG
if (isffmpeg(name)) {
return (ANIM_FFMPEG);
}
# endif
if (isavi(name)) {
return (ANIM_AVI);
}
#endif
type = IMB_ispic(name);
if (type) {
return ANIM_SEQUENCE;
}
return ANIM_NONE;
}
bool IMB_isanim(const char *filename)
{
int type;
type = imb_get_anim_type(filename);
return (type && type != ANIM_SEQUENCE);
}
bool IMB_isfloat(const ImBuf *ibuf)
{
const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->ftype(type, ibuf)) {
return (type->flag & IM_FTYPE_FLOAT) != 0;
}
}
return false;
}