Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_camera.h8
-rw-r--r--source/blender/blenkernel/BKE_image.h40
-rw-r--r--source/blender/blenkernel/BKE_node.h4
-rw-r--r--source/blender/blenkernel/BKE_scene.h21
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h11
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h18
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h13
-rw-r--r--source/blender/blenkernel/BKE_writeframeserver.h13
-rw-r--r--source/blender/blenkernel/intern/bpath.c4
-rw-r--r--source/blender/blenkernel/intern/camera.c254
-rw-r--r--source/blender/blenkernel/intern/image.c1157
-rw-r--r--source/blender/blenkernel/intern/node.c1
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/packedFile.c64
-rw-r--r--source/blender/blenkernel/intern/scene.c350
-rw-r--r--source/blender/blenkernel/intern/seqcache.c7
-rw-r--r--source/blender/blenkernel/intern/sequencer.c902
-rw-r--r--source/blender/blenkernel/intern/writeavi.c88
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c408
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c132
21 files changed, 2845 insertions, 654 deletions
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index a790715ac98..86576f9a11b 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 274
-#define BLENDER_SUBVERSION 3
+#define BLENDER_SUBVERSION 4
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 4849c66df1b..aacb7a4066b 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -136,6 +136,14 @@ bool BKE_camera_view_frame_fit_to_coords(
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
+/* Camera multi-view API */
+
+struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname);
+void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]);
+void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
+float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
+void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 3b7ba24d20b..ad191968a40 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -45,34 +45,34 @@ struct Object;
struct ImageFormatData;
struct ImagePool;
struct Main;
+struct ReportList;
#define IMA_MAX_SPACE 64
void BKE_images_init(void);
void BKE_images_exit(void);
+void BKE_image_free_packedfiles(struct Image *image);
+void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
/* call from library */
void BKE_image_free(struct Image *image);
void BKE_imbuf_stamp_info(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf);
-void BKE_image_stamp_buf(
- struct Scene *scene, struct Object *camera,
- unsigned char *rect, float *rectf, int width, int height, int channels);
+void BKE_image_stamp_buf(struct Scene *scene, struct Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels);
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf);
int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
+void BKE_imbuf_write_prepare(struct ImBuf *ibuf, struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const bool is_copy);
-
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
- const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames);
+ const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix);
void BKE_image_path_from_imtype(
char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames);
-
-bool BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
-bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
+ const char imtype, const bool use_ext, const bool use_frames, const char *suffix);
+int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
+int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
char BKE_image_ftype_to_imtype(const int ftype);
int BKE_image_imtype_to_ftype(const char imtype);
@@ -103,6 +103,7 @@ void BKE_image_tag_time(struct Image *ima);
/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
/* should be used in conjunction with an ID * to Image. */
struct ImageUser;
+struct RenderData;
struct RenderPass;
struct RenderResult;
@@ -172,11 +173,12 @@ struct Image *BKE_image_load_exists(const char *filepath);
/* adds image, adds ibuf, generates color or pattern */
struct Image *BKE_image_add_generated(
- struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4]);
+ struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d);
/* adds image from imbuf, owns imbuf */
struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf);
/* for reload, refresh, pack */
+void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser);
void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal);
void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
@@ -184,6 +186,8 @@ void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
/* ensures an Image exists for viewing nodes or render */
struct Image *BKE_image_verify_viewer(int type, const char *name);
+/* ensures the view node cache is compatible with the scene views */
+void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser);
/* called on frame change or before render */
void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
@@ -195,13 +199,23 @@ void BKE_image_update_frame(const struct Main *bmain, int cfra);
/* sets index offset for multilayer files */
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
+/* sets index offset for multiview files */
+void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
+
/* for multilayer images as well as for render-viewer */
+bool BKE_image_is_multilayer(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
+/* for multilayer images as well as for singlelayer */
+bool BKE_image_is_openexr(struct Image *ima);
+
/* for multiple slot render, call this before render */
void BKE_image_backup_render(struct Scene *scene, struct Image *ima);
-
+
+/* for singlelayer openexr saving */
+bool BKE_image_save_openexr_multiview(struct Image *ima, struct ImBuf *ibuf, const char *filepath, const int flags);
+
/* goes over all textures that use images */
void BKE_image_free_all_textures(void);
@@ -212,6 +226,7 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
void BKE_image_all_free_anim_ibufs(int except_frame);
void BKE_image_memorypack(struct Image *ima);
+void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
/* prints memory statistics for images */
void BKE_image_print_memlist(void);
@@ -243,7 +258,8 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame);
/* Guess offset for the first frame in the sequence */
int BKE_image_sequence_guess_offset(struct Image *image);
-
+bool BKE_image_has_anim(struct Image *image);
+bool BKE_image_has_packedfile(struct Image *image);
bool BKE_image_is_animated(struct Image *image);
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_file_format_set(struct Image *image, int ftype);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index ee63771406e..eca15a62c70 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -941,6 +941,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_MAP_RANGE 319
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
+#define CMP_NODE_SWITCH_VIEW 322
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -975,7 +976,8 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
/* API */
void ntreeCompositExecTree(struct Scene *scene, struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews,
- const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings);
+ const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings,
+ const char *view_name);
void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 27c89dd3a09..79778d504a5 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -70,6 +70,7 @@ void BKE_scene_free(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
/* base functions */
+struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name);
struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob);
struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob);
void BKE_scene_base_unlink(struct Scene *sce, struct Base *base);
@@ -122,6 +123,9 @@ void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct
struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl);
+struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
+bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
+
/* render profile */
int get_render_subsurf_level(const struct RenderData *r, int level);
int get_render_child_particle_number(const struct RenderData *r, int num);
@@ -142,6 +146,23 @@ int BKE_render_num_threads(const struct RenderData *r);
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
+/* multiview */
+bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
+bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd, const struct SceneRenderView *srv);
+bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
+bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
+size_t BKE_scene_multiview_num_views_get(const struct RenderData *rd);
+struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd, const int view_id);
+const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, const int view_id);
+size_t BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
+void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv, const char *filepath, char *r_filepath);
+void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd, const char *filepath, const char *view, char *r_filepath);
+const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname);
+const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const size_t view_id);
+void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char *name, char *rprefix, char **rext);
+void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height);
+size_t BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 84818276e7b..4a45489933c 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -41,6 +41,7 @@ struct Mask;
struct Scene;
struct Sequence;
struct SequenceModifierData;
+struct Stereo3dFormat;
struct StripElem;
struct bSound;
@@ -99,6 +100,7 @@ typedef struct SeqRenderData {
float motion_blur_shutter;
bool skip_cache;
bool is_proxy_render;
+ size_t view_id;
} SeqRenderData;
void BKE_sequencer_new_render_data(
@@ -223,6 +225,7 @@ void BKE_sequencer_base_clipboard_pointers_store(struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void BKE_sequence_free(struct Scene *scene, struct Sequence *seq);
+void BKE_sequence_free_anim(struct Sequence *seq);
const char *BKE_sequence_give_name(struct Sequence *seq);
void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_calc_disp(struct Scene *scene, struct Sequence *seq);
@@ -235,7 +238,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change);
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra);
-struct SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list);
+void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
@@ -355,6 +358,10 @@ typedef struct SeqLoadInfo {
int len; /* only for image strips */
char path[1024]; /* 1024 = FILE_MAX */
+ /* multiview */
+ char views_format;
+ struct Stereo3dFormat *stereo3d_format;
+
/* return values */
char name[64];
struct Sequence *seq_sound; /* for movie's */
@@ -399,7 +406,7 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq
struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load);
/* view3d draw callback, run when not in background view */
-typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, char[256]);
+typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, const char *, char[256]);
extern SequencerDrawView sequencer_view3d_cb;
/* copy/paste */
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index bc06be0295a..ca295c51f5d 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -43,16 +43,20 @@ struct ReportList;
struct Scene;
typedef struct bMovieHandle {
- int (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview);
- int (*append_movie)(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
- void (*end_movie)(void);
- int (*get_next_frame)(struct RenderData *rd, struct ReportList *reports); /* optional */
- void (*get_movie_path)(char *string, struct RenderData *rd, bool preview); /* optional */
+ int (*start_movie)(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
+ struct ReportList *reports, bool preview, const char *suffix);
+ int (*append_movie)(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, struct ReportList *reports);
+ void (*end_movie)(void *context_v);
+ int (*get_next_frame)(void *context_v, struct RenderData *rd, struct ReportList *reports); /* optional */
+ void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, const char *suffix); /* optional */
+ void *(*context_create)(void);
+ void (*context_free)(void *context_v);
} bMovieHandle;
bMovieHandle *BKE_movie_handle_get(const char imtype);
-void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview);
+void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
+void BKE_context_create(bMovieHandle *mh);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index 951fa501f9c..a40c31022e3 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -68,11 +68,11 @@ struct RenderData;
struct ReportList;
struct Scene;
-int BKE_ffmpeg_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview);
-void BKE_ffmpeg_end(void);
-int BKE_ffmpeg_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
-void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview);
+int BKE_ffmpeg_start(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix);
+void BKE_ffmpeg_end(void *context_v);
+int BKE_ffmpeg_append(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, struct ReportList *reports);
+void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset);
void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf);
@@ -82,6 +82,9 @@ bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd);
int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str);
void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_);
+void *BKE_ffmpeg_context_create(void);
+void BKE_ffmpeg_context_free(void *context_v);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h
index b7d601ea769..2f8bce31e41 100644
--- a/source/blender/blenkernel/BKE_writeframeserver.h
+++ b/source/blender/blenkernel/BKE_writeframeserver.h
@@ -40,11 +40,14 @@ struct RenderData;
struct ReportList;
struct Scene;
-int BKE_frameserver_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview);
-void BKE_frameserver_end(void);
-int BKE_frameserver_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
-int BKE_frameserver_loop(struct RenderData *rd, struct ReportList *reports);
+int BKE_frameserver_start(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
+ struct ReportList *reports, bool preview, const char *suffix);
+void BKE_frameserver_end(void *context_v);
+int BKE_frameserver_append(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char*suffix, struct ReportList *reports);
+int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports);
+void *BKE_frameserver_context_create(void);
+void BKE_frameserver_context_free(void *context_v);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index e94f30da0c5..bb3731218ed 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -423,10 +423,10 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
{
Image *ima;
ima = (Image *)id;
- if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
+ if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
- if (!ima->packedfile) {
+ if (!BKE_image_has_packedfile(ima)) {
BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 5b4d7ba8214..fec6542ac47 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -30,16 +30,19 @@
*/
#include <stdlib.h>
+#include <stddef.h>
#include "DNA_camera_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_ID.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_camera.h"
@@ -47,6 +50,7 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "GPU_compositing.h"
@@ -71,6 +75,10 @@ void *BKE_camera_add(Main *bmain, const char *name)
GPU_fx_compositor_init_dof_settings(&cam->gpu_dof);
+ /* stereoscopy 3d */
+ cam->stereo.interocular_distance = 0.065f;
+ cam->stereo.convergence_distance = 30.f * 0.065f;
+
return cam;
}
@@ -695,6 +703,250 @@ bool BKE_camera_view_frame_fit_to_coords(
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
+/******************* multiview matrix functions ***********************/
+
+static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
+{
+ copy_m4_m4(r_modelmat, camera->obmat);
+}
+
+static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
+{
+ Camera *data = (Camera *)camera->data;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ float sizemat[4][4];
+
+ float fac = 1.0f;
+ float fac_signed;
+
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
+
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
+ ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
+ {
+ return camera_model_matrix(camera, r_modelmat);
+ }
+ else {
+ float size[3];
+ mat4_to_size(size, camera->obmat);
+ size_to_mat4(sizemat, size);
+ }
+
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
+
+ fac_signed = is_left ? fac : -fac;
+
+ /* rotation */
+ if (convergence_mode == CAM_S3D_TOE) {
+ float angle;
+ float angle_sin, angle_cos;
+ float toeinmat[4][4];
+ float rotmat[4][4];
+
+ unit_m4(rotmat);
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ fac = -fac;
+ fac_signed = -fac_signed;
+ }
+
+ angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac;
+
+ angle_cos = cosf(angle * fac_signed);
+ angle_sin = sinf(angle * fac_signed);
+
+ rotmat[0][0] = angle_cos;
+ rotmat[2][0] = -angle_sin;
+ rotmat[0][2] = angle_sin;
+ rotmat[2][2] = angle_cos;
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ /* set the rotation */
+ copy_m4_m4(toeinmat, rotmat);
+ /* set the translation */
+ toeinmat[3][0] = interocular_distance * fac_signed;
+
+ /* transform */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
+ /* rotate perpendicular to the interocular line */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* translate along the interocular line */
+ unit_m4(toeinmat);
+ toeinmat[3][0] = -interocular_distance * fac_signed;
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* rotate to toe-in angle */
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ }
+ else {
+ normalize_m4_m4(r_modelmat, camera->obmat);
+
+ /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
+ translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+}
+
+/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
+void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
+{
+ BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
+ invert_m4(r_viewmat);
+}
+
+/* left is the default */
+static bool camera_is_left(const char *viewname)
+{
+ if (viewname && viewname[0] != '\0') {
+ return !STREQ(viewname, STEREO_RIGHT_NAME);
+ }
+ return true;
+}
+
+void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
+{
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ const bool is_left = camera_is_left(viewname);
+ camera_stereo3d_model_matrix(camera, is_left, r_modelmat);
+ }
+ normalize_m4(r_modelmat);
+}
+
+static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix)
+{
+ SceneRenderView *srv;
+ char name[MAX_NAME];
+ const char *camera_name = camera->id.name + 2;
+ const int len_name = strlen(camera_name);
+
+ name[0] = '\0';
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ const int len_suffix = strlen(srv->suffix);
+
+ if (len_name < len_suffix)
+ continue;
+
+ if (STREQ(camera_name + (len_name - len_suffix), srv->suffix)) {
+ BLI_snprintf(name, sizeof(name), "%.*s%s", (len_name - len_suffix), camera_name, suffix);
+ break;
+ }
+ }
+
+ if (name[0] != '\0') {
+ Base *base = BKE_scene_base_find_by_name(scene, name);
+ if (base) {
+ return base->object;
+ }
+ }
+
+ return camera;
+}
+
+/* returns the camera to be used for render */
+Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname)
+{
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ return camera;
+ }
+ else if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ return camera;
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ const char *suffix = BKE_scene_multiview_view_suffix_get(&scene->r, viewname);
+ return camera_multiview_advanced(scene, camera, suffix);
+ }
+}
+
+static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
+{
+ Camera *data = camera->data;
+ float shift = data->shiftx;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ bool is_left = true;
+
+ float fac = 1.0f;
+ float fac_signed;
+
+ if (viewname && viewname[0]) {
+ is_left = STREQ(viewname, STEREO_LEFT_NAME);
+ }
+
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
+
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
+ ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
+ {
+ return shift;
+ }
+
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
+
+ fac_signed = is_left ? fac : -fac;
+
+ /* Note: in viewport, parallel renders as offaxis, but in render it does parallel */
+ if (ELEM(convergence_mode, CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL)) {
+ shift += ((interocular_distance / data->sensor_x) * (data->lens / convergence_distance)) * fac_signed;
+ }
+
+ return shift;
+}
+
+float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname)
+{
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+ Camera *data = camera->data;
+
+ if (!is_multiview) {
+ return data->shiftx;
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ return data->shiftx;
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ return camera_stereo3d_shift_x(camera, viewname);
+ }
+}
+
+void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname)
+{
+ params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
+}
+
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings)
{
if (camera->type == OB_CAMERA) {
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 9b00a0150ad..f852d886ae9 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -99,6 +99,12 @@
static SpinLock image_spin;
+/* prototypes */
+static size_t image_num_files(struct Image *ima);
+static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r);
+static void image_update_views_format(Image *ima, ImageUser *iuser);
+static void image_add_view(Image *ima, const char *viewname, const char *filepath);
+
/* max int, to indicate we don't store sequences in ibuf */
#define IMA_NO_INDEX 0x7FEFEFEF
@@ -257,6 +263,46 @@ static void image_free_cached_frames(Image *image)
}
}
+static void image_free_packedfiles(Image *ima)
+{
+ while (ima->packedfiles.last) {
+ ImagePackedFile *imapf = ima->packedfiles.last;
+ if (imapf->packedfile) {
+ freePackedFile(imapf->packedfile);
+ }
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
+ }
+}
+
+void BKE_image_free_packedfiles(Image *ima)
+{
+ image_free_packedfiles(ima);
+}
+
+static void image_free_views(Image *ima)
+{
+ BLI_freelistN(&ima->views);
+}
+
+void BKE_image_free_views(Image *image)
+{
+ image_free_views(image);
+}
+
+static void image_free_anims(Image *ima)
+{
+ while (ima->anims.last) {
+ ImageAnim *ia = ima->anims.last;
+ if (ia->anim) {
+ IMB_free_anim(ia->anim);
+ ia->anim = NULL;
+ }
+ BLI_remlink(&ima->anims, ia);
+ MEM_freeN(ia);
+ }
+}
+
/**
* Simply free the image data from memory,
* on display the image can load again (except for render buffers).
@@ -265,8 +311,7 @@ void BKE_image_free_buffers(Image *ima)
{
image_free_cached_frames(ima);
- if (ima->anim) IMB_free_anim(ima->anim);
- ima->anim = NULL;
+ image_free_anims(ima);
if (ima->rr) {
RE_FreeRenderResult(ima->rr);
@@ -290,10 +335,9 @@ void BKE_image_free(Image *ima)
int a;
BKE_image_free_buffers(ima);
- if (ima->packedfile) {
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
- }
+
+ image_free_packedfiles(ima);
+
BKE_icon_delete(&ima->id);
ima->id.icon_id = 0;
@@ -305,6 +349,9 @@ void BKE_image_free(Image *ima)
ima->renders[a] = NULL;
}
}
+
+ image_free_views(ima);
+ MEM_freeN(ima->stereo3d_format);
}
/* only image block itself */
@@ -328,7 +375,9 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
ima->flag |= IMA_VIEW_AS_RENDER;
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
+ ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
+
return ima;
}
@@ -359,6 +408,22 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
}
}
+static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
+{
+ const ImagePackedFile *imapf_src;
+
+ BLI_listbase_clear(lb_dst);
+ for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) {
+ ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)");
+ BLI_strncpy(imapf_dst->filepath, imapf_src->filepath, sizeof(imapf_dst->filepath));
+
+ if (imapf_src->packedfile)
+ imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile);
+
+ BLI_addtail(lb_dst, imapf_dst);
+ }
+}
+
/* empty image block, of similar type and filename */
Image *BKE_image_copy(Main *bmain, Image *ima)
{
@@ -381,8 +446,10 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings);
- if (ima->packedfile)
- nima->packedfile = dupPackedFile(ima->packedfile);
+ copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles);
+
+ nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format);
+ BLI_duplicatelist(&nima->views, &ima->views);
if (ima->id.lib) {
BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id);
@@ -686,7 +753,9 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists)
BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id));
if (BLI_path_cmp(strtest, str) == 0) {
- if (ima->anim == NULL || ima->id.us == 0) {
+ if ((BKE_image_has_anim(ima) == false) ||
+ (ima->id.us == 0))
+ {
ima->id.us++; /* officially should not, it doesn't link here! */
if (ima->ok == 0)
ima->ok = IMA_OK;
@@ -774,13 +843,14 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
}
/* adds new image block, creates ImBuf and initializes color */
-Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4])
+Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d)
{
/* on save, type is changed to FILE in editsima.c */
Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
if (ima) {
- ImBuf *ibuf;
+ size_t view_id;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
/* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */
ima->gen_x = width;
@@ -790,13 +860,21 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
ima->gen_depth = depth;
copy_v4_v4(ima->gen_color, color);
- ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ for (view_id = 0; view_id < 2; view_id++) {
+ ImBuf *ibuf;
+ ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
+ image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0);
- /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
- IMB_freeImBuf(ibuf);
+ /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
+ IMB_freeImBuf(ibuf);
+ if (!stereo3d) break;
+
+ image_add_view(ima, names[view_id], "");
+ }
ima->ok = IMA_OK_LOADED;
+ if (stereo3d)
+ ima->flag |= IMA_IS_STEREO | IMA_IS_MULTIVIEW;
}
return ima;
@@ -821,17 +899,76 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
return ima;
}
+/* packs rects from memory as PNG
+ * convert multiview images to R_IMF_VIEWS_INDIVIDUAL
+ */
+static void image_memorypack_multiview(Image *ima)
+{
+ ImageView *iv;
+ size_t i;
+
+ image_free_packedfiles(ima);
+
+ for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0);
+
+ ibuf->ftype = PNG;
+ ibuf->planes = R_IMF_PLANES_RGBA;
+
+ /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
+ if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
+ BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], "");
+ }
+
+ IMB_saveiff(ibuf, iv->filepath, IB_rect | IB_mem);
+
+ if (ibuf->encodedbuffer == NULL) {
+ printf("memory save for pack error\n");
+ IMB_freeImBuf(ibuf);
+ image_free_packedfiles(ima);
+ return;
+ }
+ else {
+ ImagePackedFile *imapf;
+ PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
+
+ pf->data = ibuf->encodedbuffer;
+ pf->size = ibuf->encodedsize;
+
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ ibuf->encodedbuffer = NULL;
+ ibuf->encodedsize = 0;
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+ }
+ IMB_freeImBuf(ibuf);
+ }
+
+ if (ima->source == IMA_SRC_GENERATED) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+ ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
+}
+
/* packs rect from memory as PNG */
void BKE_image_memorypack(Image *ima)
{
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf;
+
+ if ((ima->flag & IMA_IS_MULTIVIEW))
+ return image_memorypack_multiview(ima);
+
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
if (ibuf == NULL)
return;
- if (ima->packedfile) {
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
- }
+
+ image_free_packedfiles(ima);
ibuf->ftype = PNG;
ibuf->planes = R_IMF_PLANES_RGBA;
@@ -841,11 +978,17 @@ void BKE_image_memorypack(Image *ima)
printf("memory save for pack error\n");
}
else {
+ ImagePackedFile *imapf;
PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
pf->data = ibuf->encodedbuffer;
pf->size = ibuf->encodedsize;
- ima->packedfile = pf;
+
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
+
ibuf->encodedbuffer = NULL;
ibuf->encodedsize = 0;
ibuf->userflags &= ~IB_BITMAPDIRTY;
@@ -859,6 +1002,28 @@ void BKE_image_memorypack(Image *ima)
IMB_freeImBuf(ibuf);
}
+void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
+{
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles == 1) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFile(reports, ima->name, basepath);
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ }
+ else {
+ ImageView *iv;
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ imapf->packedfile = newPackedFile(reports, iv->filepath, basepath);
+ BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ }
+ }
+}
+
void BKE_image_tag_time(Image *ima)
{
ima->lastused = PIL_check_seconds_timer_i();
@@ -1259,7 +1424,7 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else return R_IMF_IMTYPE_INVALID;
}
-static bool image_path_ensure_ext(char *string, const char imtype, const ImageFormatData *im_format)
+static bool do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format)
{
const char *extension = NULL;
const char *extension_test;
@@ -1311,7 +1476,7 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo
}
#endif
#ifdef WITH_OPENEXR
- else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
+ else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
if (!BLI_testextensie(string, extension_test = ".exr"))
extension = extension_test;
}
@@ -1369,14 +1534,14 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo
}
}
-bool BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
+int BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
{
- return image_path_ensure_ext(string, im_format->imtype, im_format);
+ return do_add_image_extension(string, im_format->imtype, im_format);
}
-bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
+int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
{
- return image_path_ensure_ext(string, imtype, NULL);
+ return do_add_image_extension(string, imtype, NULL);
}
void BKE_imformat_defaults(ImageFormatData *im_format)
@@ -1908,14 +2073,12 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
/* note: imf->planes is ignored here, its assumed the image channels
* are already set */
-int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
+void BKE_imbuf_write_prepare(ImBuf *ibuf, ImageFormatData *imf)
{
char imtype = imf->imtype;
char compress = imf->compress;
char quality = imf->quality;
- int ok;
-
if (imtype == R_IMF_IMTYPE_IRIS) {
ibuf->ftype = IMAGIC;
}
@@ -1952,7 +2115,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
}
#endif
#ifdef WITH_OPENEXR
- else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
+ else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
ibuf->ftype = OPENEXR;
if (imf->depth == R_IMF_CHAN_DEPTH_16)
ibuf->ftype |= OPENEXR_HALF;
@@ -2036,6 +2199,13 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
if (quality < 10) quality = 90;
ibuf->ftype = JPG | quality;
}
+}
+
+int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
+{
+ int ok;
+
+ BKE_imbuf_write_prepare(ibuf, imf);
BLI_make_existing_file(name);
@@ -2079,9 +2249,10 @@ int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, cons
}
-static void image_path_makepicstring(
+static void do_makepicstring(
char *string, const char *base, const char *relbase, int frame, const char imtype,
- const ImageFormatData *im_format, const short use_ext, const short use_frames)
+ const ImageFormatData *im_format, const short use_ext, const short use_frames,
+ const char *suffix)
{
if (string == NULL) return;
BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
@@ -2090,22 +2261,25 @@ static void image_path_makepicstring(
if (use_frames)
BLI_path_frame(string, frame, 4);
+ if (suffix)
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
+
if (use_ext)
- image_path_ensure_ext(string, imtype, im_format);
+ do_add_image_extension(string, imtype, im_format);
}
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
- const ImageFormatData *im_format, const bool use_ext, const bool use_frames)
+ const ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix)
{
- image_path_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames);
+ do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix);
}
void BKE_image_path_from_imtype(
char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames)
+ const char imtype, const bool use_ext, const bool use_frames, const char *view)
{
- image_path_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames);
+ do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames, view);
}
struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
@@ -2181,6 +2355,59 @@ Image *BKE_image_verify_viewer(int type, const char *name)
return ima;
}
+static void image_viewer_create_views(const RenderData *rd, Image *ima)
+{
+ SceneRenderView *srv;
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+ image_add_view(ima, srv->name, "");
+ }
+}
+
+/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */
+void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
+{
+ bool do_reset;
+
+ BLI_lock_thread(LOCK_DRAW_IMAGE);
+
+ if (BKE_scene_multiview_is_stereo3d(rd)) {
+ ima->flag |= IMA_IS_STEREO;
+ ima->flag |= IMA_IS_MULTIVIEW;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+
+ /* see if all scene render views are in the image view list */
+ do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
+ if (!do_reset) {
+ SceneRenderView *srv;
+ ImageView *iv;
+
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ srv = BLI_findstring(&rd->views, iv->name, offsetof(SceneRenderView, name));
+ if ((srv == NULL) || (BKE_scene_multiview_is_render_view_active(rd, srv) == false)) {
+ do_reset = true;
+ break;
+ }
+ }
+ }
+
+ if (do_reset) {
+ image_free_cached_frames(ima);
+ BKE_image_free_views(ima);
+
+ /* add new views */
+ image_viewer_create_views(rd, ima);
+ }
+
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
+}
+
void BKE_image_walk_all_users(const Main *mainp, void *customdata,
void callback(Image *ima, ImageUser *iuser, void *customdata))
{
@@ -2238,6 +2465,33 @@ static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdat
}
}
+static void image_init_imageuser(Image *ima, ImageUser *iuser)
+{
+ RenderResult *rr = ima->rr;
+
+ iuser->multi_index = 0;
+ iuser->layer = iuser->pass = iuser->view = 0;
+ iuser->passtype = SCE_PASS_COMBINED;
+
+ if (rr) {
+ RenderLayer *rl = rr->layers.first;
+
+ if (rl) {
+ RenderPass *rp = rl->passes.first;
+
+ if (rp)
+ iuser->passtype = rp->passtype;
+ }
+
+ BKE_image_multilayer_index(rr, iuser);
+ }
+}
+
+void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
+{
+ return image_init_imageuser(ima, iuser);
+}
+
void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
{
if (ima == NULL)
@@ -2248,8 +2502,13 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
switch (signal) {
case IMA_SIGNAL_FREE:
BKE_image_free_buffers(ima);
- if (iuser)
+
+ if (iuser) {
iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
break;
case IMA_SIGNAL_SRC_CHANGE:
if (ima->type == IMA_TYPE_UV_TEST)
@@ -2301,23 +2560,41 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_RELOAD:
/* try to repack file */
- if (ima->packedfile) {
- PackedFile *pf;
- pf = newPackedFile(NULL, ima->name, ID_BLEND_PATH(G.main, &ima->id));
- if (pf) {
- freePackedFile(ima->packedfile);
- ima->packedfile = pf;
- BKE_image_free_buffers(ima);
+ if (BKE_image_has_packedfile(ima)) {
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ /* in case there are new available files to be loaded */
+ image_free_packedfiles(ima);
+ BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(G.main, &ima->id));
}
else {
- printf("ERROR: Image not available. Keeping packed image\n");
+ ImagePackedFile *imapf;
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ PackedFile *pf;
+ pf = newPackedFile(NULL, imapf->filepath, ID_BLEND_PATH(G.main, &ima->id));
+ if (pf) {
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = pf;
+ }
+ else {
+ printf("ERROR: Image \"%s\" not available. Keeping packed image\n", imapf->filepath);
+ }
+ }
}
+
+ if (BKE_image_has_packedfile(ima))
+ BKE_image_free_buffers(ima);
}
else
BKE_image_free_buffers(ima);
- if (iuser)
+ if (iuser) {
iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
break;
case IMA_SIGNAL_USER_NEW_IMAGE:
@@ -2325,8 +2602,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
iuser->ok = 1;
if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_MULTILAYER) {
- iuser->multi_index = 0;
- iuser->layer = iuser->pass = 0;
+ image_init_imageuser(ima, iuser);
}
}
}
@@ -2368,21 +2644,34 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
return NULL;
if (iuser) {
- short index = 0, rl_index = 0, rp_index;
+ short index = 0, rv_index, rl_index = 0, rp_index;
+ bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr);
+
+ rv_index = is_stereo ? iuser->multiview_eye : iuser->view;
for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) {
rp_index = 0;
- for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++, rp_index++)
- if (iuser->layer == rl_index && iuser->pass == rp_index)
+
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++, rp_index++) {
+ if (iuser->layer == rl_index &&
+ iuser->passtype == rpass->passtype &&
+ rv_index == rpass->view_id)
+ {
break;
+ }
+ }
if (rpass)
break;
}
- if (rpass)
+ if (rpass) {
iuser->multi_index = index;
- else
+ iuser->pass = rp_index;
+ }
+ else {
iuser->multi_index = 0;
+ iuser->pass = 0;
+ }
}
if (rpass == NULL) {
rl = rr->layers.first;
@@ -2393,19 +2682,80 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
return rpass;
}
+void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
+{
+ if (iuser) {
+ bool is_stereo = (ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO);
+ if (is_stereo) {
+ iuser->multi_index = iuser->multiview_eye;
+ }
+ else {
+ if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_ex(&ima->views, iuser->view + 1))) {
+ iuser->multi_index = iuser->view = 0;
+ }
+ else {
+ iuser->multi_index = iuser->view;
+ }
+ }
+ }
+}
+
+/* if layer or pass changes, we need an index for the imbufs list */
+/* note it is called for rendered results, but it doesnt use the index! */
+/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
+bool BKE_image_is_multilayer(Image *ima)
+{
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ return true;
+ }
+ }
+ else if (ima->source == IMA_SRC_VIEWER) {
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_init_multilayer_multiview_flag(Image *ima, RenderResult *rr)
+{
+ if (rr) {
+ if (RE_RenderResult_is_stereo(rr)) {
+ ima->flag |= IMA_IS_STEREO;
+ ima->flag |= IMA_IS_MULTIVIEW;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ if (BLI_listbase_count_ex(&rr->views, 2) > 1)
+ ima->flag |= IMA_IS_MULTIVIEW;
+ else
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+}
+
RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
{
+ RenderResult *rr = NULL;
if (ima->rr) {
- return ima->rr;
+ rr = ima->rr;
}
else if (ima->type == IMA_TYPE_R_RESULT) {
if (ima->render_slot == ima->last_render_slot)
- return RE_AcquireResultRead(RE_GetRender(scene->id.name));
+ rr = RE_AcquireResultRead(RE_GetRender(scene->id.name));
else
- return ima->renders[ima->render_slot];
+ rr = ima->renders[ima->render_slot];
+
+ /* set proper multiview flag */
+ image_init_multilayer_multiview_flag(ima, rr);
}
- else
- return NULL;
+
+ return rr;
}
void BKE_image_release_renderresult(Scene *scene, Image *ima)
@@ -2419,6 +2769,18 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima)
}
}
+bool BKE_image_is_openexr(struct Image *ima)
+{
+#ifdef WITH_OPENEXR
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ return BLI_testextensie(ima->name, ".exr");
+ }
+#else
+ UNUSED_VARS(ima);
+#endif
+ return false;
+}
+
void BKE_image_backup_render(Scene *scene, Image *ima)
{
/* called right before rendering, ima->renders contains render
@@ -2439,8 +2801,155 @@ void BKE_image_backup_render(Scene *scene, Image *ima)
ima->last_render_slot = slot;
}
+/**************************** multiview save openexr *********************************/
+#ifdef WITH_OPENEXR
+static const char *image_get_view_cb(void *base, const size_t view_id)
+{
+ Image *ima = base;
+ ImageView *iv = BLI_findlink(&ima->views, view_id);
+ return iv ? iv->name : "";
+}
+#endif /* WITH_OPENEXR */
+
+#ifdef WITH_OPENEXR
+static ImBuf *image_get_buffer_cb(void *base, const size_t view_id)
+{
+ Image *ima = base;
+ ImageUser iuser = {0};
+
+ iuser.view = view_id;
+ iuser.ok = 1;
+
+ BKE_image_multiview_index(ima, &iuser);
+
+ return image_acquire_ibuf(ima, &iuser, NULL);
+}
+#endif /* WITH_OPENEXR */
+
+bool BKE_image_save_openexr_multiview(Image *ima, ImBuf *ibuf, const char *filepath, const int flags)
+{
+#ifdef WITH_OPENEXR
+ char name[FILE_MAX];
+ bool ok;
+
+ BLI_strncpy(name, filepath, sizeof(name));
+ BLI_path_abs(name, G.main->name);
+
+ ibuf->userdata = ima;
+ ok = IMB_exr_multiview_save(ibuf, name, flags, BLI_listbase_count(&ima->views), image_get_view_cb, image_get_buffer_cb);
+ ibuf->userdata = NULL;
+
+ return ok;
+#else
+ UNUSED_VARS(ima, ibuf, filepath, flags);
+ return false;
+#endif
+}
+
+/**************************** multiview load openexr *********************************/
+
+static void image_add_view(Image *ima, const char *viewname, const char *filepath)
+{
+ ImageView *iv;
+
+ iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View");
+ BLI_strncpy(iv->name, viewname, sizeof(iv->name));
+ BLI_strncpy(iv->filepath, filepath, sizeof(iv->filepath));
+
+ /* For stereo drawing we need to ensure:
+ * STEREO_LEFT_NAME == STEREO_LEFT_ID and
+ * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
+
+ if (STREQ(viewname, STEREO_LEFT_NAME)) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else if (STREQ(viewname, STEREO_RIGHT_NAME)) {
+ ImageView *left_iv = BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name));
+
+ if (left_iv == NULL) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else {
+ BLI_insertlinkafter(&ima->views, left_iv, iv);
+ }
+ }
+ else {
+ BLI_addtail(&ima->views, iv);
+ }
+}
+
+#ifdef WITH_OPENEXR
+static void image_add_view_cb(void *base, const char *str)
+{
+ Image *ima = base;
+ image_add_view(ima, str, ima->name);
+}
+
+static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const int frame)
+{
+ Image *ima = base;
+ size_t id;
+ bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
+ const char *colorspace = ima->colorspace_settings.name;
+ const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+
+ if (ibuf == NULL)
+ return;
+
+ id = BLI_findstringindex(&ima->views, str, offsetof(ImageView, name));
+
+ if (id == -1)
+ return;
+
+ if (ibuf->channels >= 3)
+ IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+ colorspace, to_colorspace, predivide);
+
+ image_assign_ibuf(ima, ibuf, id, frame);
+ IMB_freeImBuf(ibuf);
+}
+#endif /* WITH_OPENEXR */
+
+#ifdef WITH_OPENEXR
+static void image_update_multiview_flags(Image *ima)
+{
+ if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
+ ima->flag |= IMA_IS_MULTIVIEW;
+
+ if (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
+ BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)))
+ {
+ ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ }
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+}
+#endif /* WITH_OPENEXR */
+
/* after imbuf load, openexr type can return with a exrhandle open */
/* in that case we have to build a render-result */
+#ifdef WITH_OPENEXR
+static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame)
+{
+ image_free_views(ima);
+
+ IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame);
+
+ image_update_multiview_flags(ima);
+
+ IMB_exr_close(ibuf->userdata);
+}
+#endif /* WITH_OPENEXR */
+
+/* after imbuf load, openexr type can return with a exrhandle open */
+/* in that case we have to build a render-result */
+#ifdef WITH_OPENEXR
static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
{
const char *colorspace = ima->colorspace_settings.name;
@@ -2448,14 +2957,16 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
-#ifdef WITH_OPENEXR
IMB_exr_close(ibuf->userdata);
-#endif
ibuf->userdata = NULL;
if (ima->rr)
ima->rr->framenr = framenr;
+
+ /* set proper multiview flag */
+ image_init_multilayer_multiview_flag(ima, ima->rr);
}
+#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
@@ -2488,18 +2999,41 @@ static int imbuf_alpha_flags_for_image(Image *ima)
return flag;
}
-static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+/* the number of files will vary according to the stereo format */
+static size_t image_num_files(Image *ima)
+{
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BLI_listbase_count(&ima->views);
+ }
+}
+
+static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id, bool *r_assign)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
+ ImageUser iuser_t;
/* XXX temp stuff? */
if (ima->lastframe != frame)
ima->tpageflag |= IMA_TPAGE_REFRESH;
ima->lastframe = frame;
- BKE_image_user_file_path(iuser, ima, name);
+
+ if (iuser)
+ iuser_t = *iuser;
+
+ iuser_t.view = view_id;
+ BKE_image_user_file_path(&iuser_t, ima, name);
flag = IB_rect | IB_multilayer;
flag |= imbuf_alpha_flags_for_image(ima);
@@ -2520,25 +3054,78 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
#ifdef WITH_OPENEXR
/* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
if (ibuf->ftype == OPENEXR && ibuf->userdata) {
- image_create_multilayer(ima, ibuf, frame);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
+ /* handle singlelayer multiview case assign ibuf based on available views */
+ if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) {
+ image_create_multiview(ima, ibuf, frame);
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+ image_create_multilayer(ima, ibuf, frame);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
}
else {
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ *r_assign = true;
}
#else
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ *r_assign = true;
#endif
}
- else
- ima->ok = 0;
- if (iuser)
- iuser->ok = ima->ok;
+ return ibuf;
+}
+
+static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ bool assign = false;
+
+ if (!is_multiview) {
+ ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ }
+ else {
+ size_t i;
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
return ibuf;
}
@@ -2595,46 +3182,52 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
return ibuf;
}
-
-static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
+static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id)
{
struct ImBuf *ibuf = NULL;
+ ImageAnim *ia;
- ima->lastframe = frame;
+ ia = BLI_findlink(&ima->anims, view_id);
- if (ima->anim == NULL) {
+ if (ia->anim == NULL) {
char str[FILE_MAX];
int flags = IB_rect;
+ ImageUser iuser_t;
+
if (ima->flag & IMA_DEINTERLACE) {
flags |= IB_animdeinterlace;
}
- BKE_image_user_file_path(iuser, ima, str);
+ if (iuser)
+ iuser_t = *iuser;
+
+ iuser_t.view = view_id;
+
+ BKE_image_user_file_path(&iuser_t, ima, str);
/* FIXME: make several stream accessible in image editor, too*/
- ima->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
+ ia->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
/* let's initialize this user */
- if (ima->anim && iuser && iuser->frames == 0)
- iuser->frames = IMB_anim_get_duration(ima->anim,
+ if (ia->anim && iuser && iuser->frames == 0)
+ iuser->frames = IMB_anim_get_duration(ia->anim,
IMB_TC_RECORD_RUN);
}
- if (ima->anim) {
- int dur = IMB_anim_get_duration(ima->anim,
+ if (ia->anim) {
+ int dur = IMB_anim_get_duration(ia->anim,
IMB_TC_RECORD_RUN);
int fra = frame - 1;
if (fra < 0) fra = 0;
if (fra > (dur - 1)) fra = dur - 1;
ibuf = IMB_makeSingleUser(
- IMB_anim_absolute(ima->anim, fra,
+ IMB_anim_absolute(ia->anim, fra,
IMB_TC_RECORD_RUN,
IMB_PROXY_NONE));
if (ibuf) {
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
}
else
ima->ok = 0;
@@ -2642,67 +3235,223 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
else
ima->ok = 0;
+ return ibuf;
+}
+
+static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ size_t i;
+
+ if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) {
+ image_free_anims(ima);
+
+ for (i = 0; i < totfiles; i++) {
+ /* allocate the ImageAnim */
+ ImageAnim *ia = MEM_callocN(sizeof(ImageAnim), "Image Anim");
+ BLI_addtail(&ima->anims, ia);
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_movie_single(ima, iuser, frame, 0);
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ else {
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views (movie) Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+ ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
+ }
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ else {
+ ima->ok = 0;
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
+
if (iuser)
iuser->ok = ima->ok;
return ibuf;
}
-/* warning, 'iuser' can be NULL */
-static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
+static ImBuf *load_image_single(
+ Image *ima, ImageUser *iuser, int cfra,
+ const size_t view_id,
+ const bool has_packed,
+ bool *r_assign)
{
- struct ImBuf *ibuf;
- char str[FILE_MAX];
- int assign = 0, flag;
-
- /* always ensure clean ima */
- BKE_image_free_buffers(ima);
+ char filepath[FILE_MAX];
+ struct ImBuf *ibuf = NULL;
+ int flag;
/* is there a PackedFile with this image ? */
- if (ima->packedfile) {
+ if (has_packed) {
+ ImagePackedFile *imapf;
+
flag = IB_rect | IB_multilayer;
flag |= imbuf_alpha_flags_for_image(ima);
- ibuf = IMB_ibImageFromMemory((unsigned char *)ima->packedfile->data, ima->packedfile->size, flag,
- ima->colorspace_settings.name, "<packed data>");
+ imapf = BLI_findlink(&ima->packedfiles, view_id);
+ ibuf = IMB_ibImageFromMemory(
+ (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag,
+ ima->colorspace_settings.name, "<packed data>");
}
else {
+ ImageUser iuser_t;
+
flag = IB_rect | IB_multilayer | IB_metadata;
flag |= imbuf_alpha_flags_for_image(ima);
- /* get the right string */
+ /* get the correct filepath */
BKE_image_user_frame_calc(iuser, cfra, 0);
- BKE_image_user_file_path(iuser, ima, str);
+
+ if (iuser)
+ iuser_t = *iuser;
+ else
+ iuser_t.framenr = ima->lastframe;
+
+ iuser_t.view = view_id;
+
+ BKE_image_user_file_path(&iuser_t, ima, filepath);
/* read ibuf */
- ibuf = IMB_loadiffname(str, flag, ima->colorspace_settings.name);
+ ibuf = IMB_loadiffname(filepath, flag, ima->colorspace_settings.name);
}
if (ibuf) {
- /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+#ifdef WITH_OPENEXR
if (ibuf->ftype == OPENEXR && ibuf->userdata) {
- image_create_multilayer(ima, ibuf, cfra);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
+ if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) {
+ /* handle singlelayer multiview case assign ibuf based on available views */
+ image_create_multiview(ima, ibuf, cfra);
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+ image_create_multilayer(ima, ibuf, cfra);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
}
else {
image_initialize_after_load(ima, ibuf);
- assign = 1;
+ *r_assign = true;
/* check if the image is a font image... */
detectBitmapFont(ibuf);
/* make packed file for autopack */
- if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK))
- ima->packedfile = newPackedFile(NULL, str, ID_BLEND_PATH(G.main, &ima->id));
+ if ((has_packed == false) && (G.fileflags & G_AUTOPACK)) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ BLI_strncpy(imapf->filepath, filepath, sizeof(imapf->filepath));
+ imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH(G.main, &ima->id));
+ }
}
+#else
+ image_initialize_after_load(ima, ibuf);
+ *r_assign = true;
+#endif
}
- else
+ else {
ima->ok = 0;
+ }
- if (assign)
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ return ibuf;
+}
+
+/* warning, 'iuser' can be NULL
+ * note: Image->views was already populated (in image_update_views_format)
+ */
+static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
+{
+ struct ImBuf *ibuf = NULL;
+ bool assign = false;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ bool has_packed = BKE_image_has_packedfile(ima);
+
+ /* always ensure clean ima */
+ BKE_image_free_buffers(ima);
+
+ /* this should never happen, but just playing safe */
+ if (has_packed) {
+ if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ image_free_packedfiles(ima);
+ has_packed = false;
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
+ }
+ else {
+ size_t i;
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+ BLI_assert(totviews > 0);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ /* return the original requested ImBuf */
+ i = iuser && iuser->multi_index < totviews ? iuser->multi_index : 0;
+ ibuf = ibuf_arr[i];
+
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ }
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
if (iuser)
iuser->ok = ima->ok;
@@ -2756,9 +3505,10 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
float *rectf, *rectz;
unsigned int *rect;
float dither;
- int channels, layer, pass;
+ int channels, layer, passtype;
ImBuf *ibuf;
int from_render = (ima->render_slot == ima->last_render_slot);
+ int actview;
bool byte_buffer_in_display_space = false;
if (!(iuser && iuser->scene))
@@ -2772,14 +3522,18 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
channels = 4;
layer = iuser->layer;
- pass = iuser->pass;
+ passtype = iuser->passtype;
+ actview = iuser->view;
+
+ if ((ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO))
+ actview = iuser->multiview_eye;
if (from_render) {
- RE_AcquireResultImage(re, &rres);
+ RE_AcquireResultImage(re, &rres, actview);
}
else if (ima->renders[ima->render_slot]) {
rres = *(ima->renders[ima->render_slot]);
- rres.have_combined = rres.rectf != NULL;
+ rres.have_combined = RE_RenderViewGetRectf(&rres, actview) != NULL;
}
else
memset(&rres, 0, sizeof(RenderResult));
@@ -2819,24 +3573,18 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
if (rl) {
RenderPass *rpass;
- /* there's no combined pass, is in renderlayer itself */
- if (pass == 0) {
- rectf = rl->rectf;
- if (rectf == NULL) {
- /* Happens when Save Buffers is enabled.
- * Use display buffer stored in the render layer.
- */
- rect = (unsigned int *) rl->display_buffer;
- byte_buffer_in_display_space = true;
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ if (passtype == rpass->passtype &&
+ actview == rpass->view_id)
+ {
+ break;
}
}
- else {
- rpass = BLI_findlink(&rl->passes, pass - 1);
- if (rpass) {
- channels = rpass->channels;
- rectf = rpass->rect;
- dither = 0.0f; /* don't dither passes */
- }
+
+ if (rpass) {
+ channels = rpass->channels;
+ rectf = rpass->rect;
+ dither = 0.0f; /* don't dither passes */
}
for (rpass = rl->passes.first; rpass; rpass = rpass->next)
@@ -2925,9 +3673,31 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
return ibuf;
}
+static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
+{
+ const bool is_multilayer = BKE_image_is_multilayer(ima);
+ const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL);
+
+ if (is_multilayer) {
+ return iuser ? iuser->multi_index : IMA_NO_INDEX;
+ }
+ else if (is_backdrop) {
+ if ((ima->flag & IMA_IS_STEREO)) {
+ /* backdrop hackaround (since there is no iuser */
+ return ima->eye;
+ }
+ }
+ else if ((ima->flag & IMA_IS_MULTIVIEW)) {
+ return iuser ? iuser->multi_index : 0;
+ }
+
+ return IMA_NO_INDEX;
+}
+
static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
int frame = 0, index = 0;
+ index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
@@ -2939,7 +3709,6 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
frame = iuser ? iuser->framenr : ima->lastframe;
- index = iuser ? iuser->multi_index : IMA_NO_INDEX;
}
}
@@ -2958,10 +3727,12 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame,
ImBuf *ibuf = NULL;
int frame = 0, index = 0;
+ index = image_get_multiview_index(ima, iuser);
+
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
/* XXX temp stuff? */
if (ima->lastframe != frame)
ima->tpageflag |= IMA_TPAGE_REFRESH;
@@ -2970,7 +3741,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame,
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
/* XXX temp stuff? */
if (ima->lastframe != frame) {
@@ -2990,18 +3761,17 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame,
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
frame = iuser ? iuser->framenr : ima->lastframe;
- index = iuser ? iuser->multi_index : IMA_NO_INDEX;
ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
else if (ima->type == IMA_TYPE_MULTILAYER)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
}
else if (ima->source == IMA_SRC_GENERATED) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
}
else if (ima->source == IMA_SRC_VIEWER) {
/* always verify entirely, not that this shouldn't happen
@@ -3085,7 +3855,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
if (ima->gen_depth == 0) ima->gen_depth = 24;
ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_depth, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type,
ima->gen_color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ image_assign_ibuf(ima, ibuf, index, 0);
ima->ok = IMA_OK_LOADED;
}
else if (ima->source == IMA_SRC_VIEWER) {
@@ -3103,13 +3873,13 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
/* XXX anim play for viewer nodes not yet supported */
frame = 0; // XXX iuser ? iuser->framenr : 0;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
if (!ibuf) {
/* Composite Viewer, all handled in compositor */
/* fake ibuf, will be filled in compositor */
- ibuf = IMB_allocImBuf(256, 256, 32, IB_rect);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat);
+ image_assign_ibuf(ima, ibuf, index, frame);
}
}
}
@@ -3409,7 +4179,13 @@ void BKE_image_update_frame(const Main *bmain, int cfra)
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
- BLI_strncpy(filepath, ima->name, FILE_MAX);
+ if ((ima->flag & IMA_IS_MULTIVIEW) && (ima->rr == NULL)) {
+ ImageView *iv = BLI_findlink(&ima->views, iuser->view);
+ BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(filepath, ima->name, FILE_MAX);
+ }
if (ima->source == IMA_SRC_SEQUENCE) {
char head[FILE_MAX], tail[FILE_MAX];
@@ -3545,6 +4321,16 @@ int BKE_image_sequence_guess_offset(Image *image)
return atoi(num);
}
+bool BKE_image_has_anim(Image *ima)
+{
+ return (BLI_listbase_is_empty(&ima->anims) == false);
+}
+
+bool BKE_image_has_packedfile(Image *ima)
+{
+ return (BLI_listbase_is_empty(&ima->packedfiles) == false);
+}
+
/**
* Checks the image buffer changes (not keyframed values)
*
@@ -3675,3 +4461,88 @@ ImBuf *BKE_image_get_first_ibuf(Image *image)
return ibuf;
}
+
+static void image_update_views_format(Image *ima, ImageUser *iuser)
+{
+ SceneRenderView *srv;
+ ImageView *iv;
+ Scene *scene = iuser->scene;
+ const bool is_multiview = ((scene->r.scemode & R_MULTIVIEW) != 0) &&
+ ((ima->flag & IMA_USE_VIEWS) != 0);
+
+ /* reset the image views */
+ BKE_image_free_views(ima);
+
+ if (!is_multiview) {
+ goto monoview;
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ size_t i;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ ima->flag |= IMA_IS_MULTIVIEW;
+ ima->flag |= IMA_IS_STEREO;
+
+ for (i = 0; i < 2; i++) {
+ image_add_view(ima, names[i], ima->name);
+ }
+ return;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ char prefix[FILE_MAX] = {'\0'};
+ char *name = ima->name;
+ char *ext = NULL;
+
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] == '\0') {
+ goto monoview;
+ }
+
+ /* create all the image views */
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ char filepath[FILE_MAX];
+ BLI_snprintf(filepath, sizeof(filepath), "%s%s%s", prefix, srv->suffix, ext);
+ image_add_view(ima, srv->name, filepath);
+ }
+ }
+
+ /* check if the files are all available */
+ iv = ima->views.last;
+ while (iv) {
+ int file;
+ char str[FILE_MAX];
+
+ BLI_strncpy(str, iv->filepath, sizeof(str));
+ BLI_path_abs(str, G.main->name);
+
+ /* exists? */
+ file = BLI_open(str, O_BINARY | O_RDONLY, 0);
+ if (file == -1) {
+ ImageView *iv_del = iv;
+ iv = iv->prev;
+ BLI_remlink(&ima->views, iv_del);
+ MEM_freeN(iv_del);
+ }
+ else {
+ iv = iv->prev;
+ }
+ close(file);
+ }
+
+ /* all good */
+ if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
+ ima->flag |= IMA_IS_MULTIVIEW;
+ if (BKE_scene_multiview_is_stereo3d(&scene->r))
+ ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+monoview:
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ BKE_image_free_views(ima);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 7f3db700534..0d375b0dbeb 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -3475,6 +3475,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_bokehimage();
register_node_type_cmp_bokehblur();
register_node_type_cmp_switch();
+ register_node_type_cmp_switch_view();
register_node_type_cmp_pixelate();
register_node_type_cmp_mask();
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 81460ecdcc9..b89b5ab4bbc 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -1002,7 +1002,7 @@ static void cache_filename(char *string, const char *path, const char *relbase,
BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
- BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true);
+ BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
}
/* silly functions but useful to inline when the args do a lot of indirections */
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 9b429b356b4..61e39d0ad47 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -128,8 +128,8 @@ int countPackedFiles(Main *bmain)
/* let's check if there are packed files... */
for (ima = bmain->image.first; ima; ima = ima->id.next)
- if (ima->packedfile)
- count++;
+ if (BKE_image_has_packedfile(ima))
+ count ++;
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
if (vf->packedfile)
@@ -232,9 +232,9 @@ void packAll(Main *bmain, ReportList *reports)
int tot = 0;
for (ima = bmain->image.first; ima; ima = ima->id.next) {
- if (ima->packedfile == NULL && ima->id.lib == NULL) {
+ if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) {
if (ima->source == IMA_SRC_FILE) {
- ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
+ BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
}
else if (BKE_image_is_animated(ima)) {
@@ -564,23 +564,47 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
int unpackImage(ReportList *reports, Image *ima, int how)
{
- char localname[FILE_MAX], absname[FILE_MAX];
- char *newname;
int ret_value = RET_ERROR;
-
+
if (ima != NULL && ima->name[0]) {
- unpack_generate_paths(ima->name, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, absname, localname, ima->packedfile, how);
- if (newname != NULL) {
- ret_value = RET_OK;
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
- BLI_strncpy(ima->name, newname, sizeof(ima->name));
- MEM_freeN(newname);
- BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ while (ima->packedfiles.last) {
+ char localname[FILE_MAX], absname[FILE_MAX];
+ char *newname;
+ ImagePackedFile *imapf = ima->packedfiles.last;
+
+ unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
+ newname = unpackFile(reports, absname, localname, imapf->packedfile, how);
+
+ if (newname != NULL) {
+ ImageView *iv;
+
+ ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = NULL;
+
+ /* update the new corresponding view filepath */
+ iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
+ if (iv) {
+ BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
+ }
+
+ /* keep the new name in the image for non-pack specific reasons */
+ BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+ MEM_freeN(newname);
+ }
+ else {
+ ret_value = RET_ERROR;
+ }
+
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
}
}
-
+
+ if (ret_value == RET_OK) {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+
return(ret_value);
}
@@ -636,7 +660,7 @@ void unpackAll(Main *bmain, ReportList *reports, int how)
bSound *sound;
for (ima = bmain->image.first; ima; ima = ima->id.next)
- if (ima->packedfile)
+ if (BKE_image_has_packedfile(ima))
unpackImage(reports, ima, how);
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
@@ -655,7 +679,7 @@ bool BKE_pack_check(ID *id)
case ID_IM:
{
Image *ima = (Image *)id;
- return ima->packedfile != NULL;
+ return BKE_image_has_packedfile(ima);
}
case ID_VF:
{
@@ -683,7 +707,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
case ID_IM:
{
Image *ima = (Image *)id;
- if (ima->packedfile) {
+ if (BKE_image_has_packedfile(ima)) {
unpackImage(reports, ima, how);
}
break;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3b48de13553..443671f5a61 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -92,6 +92,7 @@
#include "PIL_time.h"
#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
#include "bmesh.h"
@@ -157,14 +158,16 @@ Scene *BKE_scene_copy(Scene *sce, int type)
Base *base, *obase;
if (type == SCE_COPY_EMPTY) {
- ListBase lb;
+ ListBase rl, rv;
/* XXX. main should become an arg */
scen = BKE_scene_add(G.main, sce->id.name + 2);
- lb = scen->r.layers;
+ rl = scen->r.layers;
+ rv = scen->r.views;
scen->r = sce->r;
- scen->r.layers = lb;
+ scen->r.layers = rl;
scen->r.actlay = 0;
+ scen->r.views = rv;
scen->unit = sce->unit;
scen->physics_settings = sce->physics_settings;
scen->gm = sce->gm;
@@ -197,6 +200,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
BLI_duplicatelist(&(scen->markers), &(sce->markers));
BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces));
BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers));
+ BLI_duplicatelist(&(scen->r.views), &(sce->r.views));
BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets));
if (sce->nodetree) {
@@ -390,6 +394,7 @@ void BKE_scene_free(Scene *sce)
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
BLI_freelistN(&sce->r.layers);
+ BLI_freelistN(&sce->r.views);
if (sce->toolsettings) {
if (sce->toolsettings->vpaint) {
@@ -437,6 +442,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
ParticleEditSettings *pset;
int a;
const char *colorspace_name;
+ SceneRenderView *srv;
sce = BKE_libblock_alloc(bmain, ID_SCE, name);
sce->lay = sce->layact = 1;
@@ -628,7 +634,16 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
BKE_scene_add_render_layer(sce, NULL);
-
+
+ /* multiview - stereo */
+ BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
+ srv = sce->r.views.first;
+ BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
+
+ BKE_scene_add_render_view(sce, STEREO_RIGHT_NAME);
+ srv = sce->r.views.last;
+ BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
+
/* game data */
sce->gm.stereoflag = STEREO_NOSTEREO;
sce->gm.stereomode = STEREO_ANAGLYPH;
@@ -701,6 +716,19 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
+Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
+{
+ Base *base;
+
+ for (base = scene->base.first; base; base = base->next) {
+ if (STREQ(base->object->id.name + 2, name)) {
+ break;
+ }
+ }
+
+ return base;
+}
+
Base *BKE_scene_base_find(Scene *scene, Object *ob)
{
return BLI_findptr(&scene->base, ob, offsetof(Base, object));
@@ -1892,6 +1920,42 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
return true;
}
+/* return default view */
+SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
+{
+ SceneRenderView *srv;
+
+ if (!name)
+ name = DATA_("RenderView");
+
+ srv = MEM_callocN(sizeof(SceneRenderView), "new render view");
+ BLI_strncpy(srv->name, name, sizeof(srv->name));
+ BLI_uniquename(&sce->r.views, srv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(srv->name));
+ BLI_addtail(&sce->r.views, srv);
+
+ return srv;
+}
+
+bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
+{
+ const int act = BLI_findindex(&scene->r.views, srv);
+
+ if (act == -1) {
+ return false;
+ }
+ else if (scene->r.views.first == scene->r.views.last) {
+ /* ensure 1 view is kept */
+ return false;
+ }
+
+ BLI_remlink(&scene->r.views, srv);
+ MEM_freeN(srv);
+
+ scene->r.actview = 0;
+
+ return true;
+}
+
/* render simplification */
int get_render_subsurf_level(const RenderData *r, int lvl)
@@ -2062,3 +2126,281 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
return value;
}
}
+
+/******************** multiview *************************/
+
+size_t BKE_scene_multiview_num_views_get(const RenderData *rd)
+{
+ SceneRenderView *srv;
+ size_t totviews = 0;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ if (BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name))) {
+ totviews++;
+ }
+
+ if (BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name))) {
+ totviews++;
+ }
+ }
+ else {
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+ }
+ }
+ return totviews;
+}
+
+bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
+{
+ SceneRenderView *srv[2];
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ srv[0] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ srv[1] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+
+ return (srv[0] && ((srv[0]->viewflag & SCE_VIEW_DISABLE) == 0) &&
+ srv[1] && ((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
+}
+
+/* return whether to render this SceneRenderView */
+bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
+{
+ if (srv == NULL)
+ return false;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ if ((srv->viewflag & SCE_VIEW_DISABLE))
+ return false;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
+ return true;
+
+ /* SCE_VIEWS_SETUP_BASIC */
+ if (STREQ(srv->name, STEREO_LEFT_NAME) ||
+ STREQ(srv->name, STEREO_RIGHT_NAME))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/* return true if viewname is the first or if the name is NULL or not found */
+bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ if ((!viewname) || (!viewname[0]))
+ return true;
+
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
+
+ return true;
+}
+
+/* return true if viewname is the last or if the name is NULL or not found */
+bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ if ((!viewname) || (!viewname[0]))
+ return true;
+
+ for (srv = rd->views.last; srv; srv = srv->prev) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
+
+ return true;
+}
+
+SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd, const int view_id)
+{
+ SceneRenderView *srv;
+ size_t nr;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return NULL;
+
+ nr = 0;
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (nr++ == view_id)
+ return srv;
+ }
+ }
+ return srv;
+}
+
+const char *BKE_scene_multiview_render_view_name_get(const RenderData *rd, const int view_id)
+{
+ SceneRenderView *srv = BKE_scene_multiview_render_view_findindex(rd, view_id);
+
+ if (srv)
+ return srv->name;
+ else
+ return "";
+}
+
+size_t BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+ size_t nr;
+
+ if ((!rd) || ((rd->scemode & R_MULTIVIEW) == 0))
+ return 0;
+
+ if ((!viewname) || (!viewname[0]))
+ return 0;
+
+ nr = 0;
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (STREQ(viewname, srv->name)) {
+ return nr;
+ }
+ else {
+ nr += 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void BKE_scene_multiview_filepath_get(
+ SceneRenderView *srv, const char *filepath,
+ char *r_filepath)
+{
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
+}
+
+/**
+ * When multiview is not used the filepath is as usual (e.g., ``Image.jpg``).
+ * When multiview is on, even if only one view is enabled the view is incorporated
+ * into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render
+ * individual views.
+ */
+void BKE_scene_multiview_view_filepath_get(
+ const RenderData *rd, const char *filepath, const char *viewname,
+ char *r_filepath)
+{
+ SceneRenderView *srv;
+ char suffix[FILE_MAX];
+
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ BLI_strncpy(suffix, srv->suffix, sizeof(suffix));
+ else
+ BLI_strncpy(suffix, viewname, sizeof(suffix));
+
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, suffix, "");
+}
+
+const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((viewname == NULL) || (viewname[0] == '\0'))
+ return viewname;
+
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ return srv->suffix;
+ else
+ return viewname;
+}
+
+const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const size_t view_id)
+{
+ if ((rd->scemode & R_MULTIVIEW) == 0) {
+ return "";
+ }
+ else {
+ const char *viewname = BKE_scene_multiview_render_view_name_get(rd, view_id);
+ return BKE_scene_multiview_view_suffix_get(rd, viewname);
+ }
+}
+
+void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *name, char *rprefix, char **rext)
+{
+ SceneRenderView *srv;
+ size_t index_act;
+ char *suf_act;
+ const char delims[] = {'.', '\0'};
+
+ rprefix[0] = '\0';
+
+ /* begin of extension */
+ index_act = BLI_str_rpartition(name, delims, rext, &suf_act);
+ BLI_assert(index_act > 0);
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ size_t len = strlen(srv->suffix);
+ if (STREQLEN(*rext - len, srv->suffix, len)) {
+ BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1);
+ break;
+ }
+ }
+ }
+}
+
+void BKE_scene_multiview_videos_dimensions_get(
+ const RenderData *rd, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ if ((rd->scemode & R_MULTIVIEW) &&
+ rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D)
+ {
+ IMB_stereo3d_write_dimensions(
+ rd->im_format.stereo3d_format.display_mode,
+ (rd->im_format.stereo3d_format.flag & S3D_SQUEEZED_FRAME) != 0,
+ width, height,
+ r_width, r_height);
+ }
+ else {
+ *r_width = width;
+ *r_height = height;
+ }
+}
+
+size_t BKE_scene_multiview_num_videos_get(const RenderData *rd)
+{
+ if (BKE_imtype_is_movie(rd->im_format.imtype) == false)
+ return 0;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ if (rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ return BKE_scene_multiview_num_views_get(rd);
+ }
+}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index 41f17665065..abfc858fd03 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
#include "IMB_moviecache.h"
#include "IMB_imbuf.h"
@@ -41,6 +42,7 @@
#include "BLI_listbase.h"
#include "BKE_sequencer.h"
+#include "BKE_scene.h"
typedef struct SeqCacheKey {
struct Sequence *seq;
@@ -77,7 +79,9 @@ static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
(a->bmain != b->bmain) ||
(a->scene != b->scene) ||
(a->motion_blur_shutter != b->motion_blur_shutter) ||
- (a->motion_blur_samples != b->motion_blur_samples));
+ (a->motion_blur_samples != b->motion_blur_samples) ||
+ (a->scene->r.views_format != b->scene->r.views_format) ||
+ (a->view_id != b->view_id));
}
static unsigned int seq_hash_render_data(const SeqRenderData *a)
@@ -89,6 +93,7 @@ static unsigned int seq_hash_render_data(const SeqRenderData *a)
rval ^= ((intptr_t) a->scene) << 6;
rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
rval ^= a->motion_blur_samples << 24;
+ rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 32;
return rval;
}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 721555097d7..942426febdd 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -53,6 +53,12 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#else
+# include <unistd.h>
+#endif
+
#include "BLF_translation.h"
#include "BKE_animsys.h"
@@ -89,6 +95,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, float cfra);
static void seq_free_animdata(Scene *scene, Sequence *seq);
static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float);
+static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview);
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id);
/* **** XXX ******** */
#define SELECT 1
@@ -181,10 +189,7 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
if (seq->strip)
seq_free_strip(seq->strip);
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
+ BKE_sequence_free_anim(seq);
if (seq->type & SEQ_TYPE_EFFECT) {
struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
@@ -196,6 +201,10 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
((ID *)seq->sound)->us--;
}
+ if (seq->stereo3d_format) {
+ MEM_freeN(seq->stereo3d_format);
+ }
+
/* clipboard has no scene and will never have a sound handle or be active
* same goes to sequences copy for proxy rebuild job
*/
@@ -240,6 +249,22 @@ void BKE_sequence_free(Scene *scene, Sequence *seq)
BKE_sequence_free_ex(scene, seq, true);
}
+/* Function to free imbuf and anim data on changes */
+void BKE_sequence_free_anim(Sequence *seq)
+{
+ while (seq->anims.last) {
+ StripAnim *sanim = seq->anims.last;
+ BLI_remlink(&seq->anims, sanim);
+
+ if (sanim->anim) {
+ IMB_free_anim(sanim->anim);
+ sanim->anim = NULL;
+ }
+
+ MEM_freeN(sanim);
+ }
+}
+
/* cache must be freed before calling this function
* since it leaves the seqbase in an invalid state */
static void seq_free_sequence_recurse(Scene *scene, Sequence *seq)
@@ -537,6 +562,7 @@ void BKE_sequencer_new_render_data(
r_context->motion_blur_shutter = 0;
r_context->skip_cache = false;
r_context->is_proxy_render = false;
+ r_context->view_id = 0;
}
/* ************************* iterator ************************** */
@@ -771,10 +797,17 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq)
}
}
+static void seq_multiview_name(Scene *scene, const size_t view_id, const char *prefix,
+ const char *ext, char *r_path, size_t r_size)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
+}
+
/* note: caller should run BKE_sequence_calc(scene, seq) after */
void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_range)
{
- char str[FILE_MAX];
+ char path[FILE_MAX];
int prev_startdisp = 0, prev_enddisp = 0;
/* note: don't rename the strip, will break animation curves */
@@ -807,22 +840,67 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
break;
}
case SEQ_TYPE_MOVIE:
- BLI_join_dirfile(str, sizeof(str), seq->strip->dir,
+ {
+ StripAnim *sanim;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
seq->strip->stripdata->name);
- BLI_path_abs(str, G.main->name);
+ BLI_path_abs(path, G.main->name);
+
+ BKE_sequence_free_anim(seq);
+
+ if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ int i = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
- if (seq->anim) IMB_free_anim(seq->anim);
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ struct anim *anim;
+ char str[FILE_MAX];
- seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ seq_anim_add_suffix(scene, anim, i);
- if (!seq->anim) {
+ if (anim) {
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ struct anim *anim;
+ anim = openanim(path, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ if (anim) {
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+
+ /* use the first video as reference for everything */
+ sanim = seq->anims.first;
+
+ if ((!sanim) || (!sanim->anim)) {
return;
}
- seq->len = IMB_anim_get_duration(seq->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
-
- seq->anim_preseek = IMB_anim_get_preseek(seq->anim);
+ seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
+
+ seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
seq->len -= seq->anim_startofs;
seq->len -= seq->anim_endofs;
@@ -830,6 +908,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
seq->len = 0;
}
break;
+ }
case SEQ_TYPE_MOVIECLIP:
if (seq->clip == NULL)
return;
@@ -1297,6 +1376,7 @@ typedef struct SeqIndexBuildContext {
int size_flags;
int quality;
bool overwrite;
+ size_t view_id;
Main *bmain;
Scene *scene;
@@ -1336,44 +1416,59 @@ static double seq_rendersize_to_scale_factor(int size)
return 0.25;
}
-static void seq_open_anim_file(Editing *ed, Sequence *seq, bool openfile)
+/* the number of files will vary according to the stereo format */
+static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview)
+{
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BKE_scene_multiview_num_views_get(&scene->r);
+ }
+}
+
+static void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
+{
+ char dir[FILE_MAX];
+ char fname[FILE_MAXFILE];
+
+ IMB_anim_get_fname(anim, fname, FILE_MAXFILE);
+ BLI_strncpy(dir, base_dir, sizeof(dir));
+ BLI_path_append(dir, sizeof(dir), fname);
+ IMB_anim_set_index_dir(anim, dir);
+}
+
+static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
{
+ char dir[FILE_MAX];
char name[FILE_MAX];
StripProxy *proxy;
+ bool use_proxy;
+ bool is_multiview_loaded = false;
+ Editing *ed = scene->ed;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
- if (seq->anim != NULL) {
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
return;
}
+ /* reset all the previously created anims */
+ BKE_sequence_free_anim(seq);
+
BLI_join_dirfile(name, sizeof(name),
seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, G.main->name);
-
- if (openfile) {
- seq->anim = openanim(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- else {
- seq->anim = openanim_noload(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
-
- if (seq->anim == NULL) {
- return;
- }
proxy = seq->strip->proxy;
- if (proxy == NULL) {
- return;
- }
-
- if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) ||
- (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE))
- {
- char dir[FILE_MAX];
- char fname[FILE_MAXFILE];
+ use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
+ (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
+ if (use_proxy) {
if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
if (ed->proxy_dir[0] == 0)
BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
@@ -1383,21 +1478,93 @@ static void seq_open_anim_file(Editing *ed, Sequence *seq, bool openfile)
else {
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
}
+ BLI_path_abs(dir, G.main->name);
+ }
- IMB_anim_get_fname(seq->anim, fname, FILE_MAXFILE);
- BLI_path_append(dir, sizeof(dir), fname);
+ if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ int i;
- BLI_path_abs(dir, G.main->name);
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+ char str[FILE_MAX];
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- IMB_anim_set_index_dir(seq->anim, dir);
+ BLI_addtail(&seq->anims, sanim);
+
+ BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext);
+
+ if (openfile) {
+ sanim->anim = openanim(
+ str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ seq_anim_add_suffix(scene, sanim->anim, i);
+
+ if (sanim->anim == NULL) {
+ if (openfile) {
+ sanim->anim = openanim(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ /* no individual view files - monoscopic, stereo 3d or exr multiview */
+ totfiles = 1;
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+ is_multiview_loaded = true;
+ }
}
-}
+ if (is_multiview_loaded == false) {
+ StripAnim *sanim;
+
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
-static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name)
+ if (openfile) {
+ sanim->anim = openanim(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+}
+
+static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const size_t view_id)
{
int frameno;
char dir[PROXY_MAXFILE];
+ StripAnim *sanim;
+ char suffix[24] = {'\0'};
StripProxy *proxy = seq->strip->proxy;
if (!proxy) {
@@ -1412,23 +1579,25 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
* have both, a directory full of jpeg files and proxy avis, so
* sorry folks, please rebuild your proxies... */
- if (seq->anim && ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ sanim = BLI_findlink(&seq->anims, view_id);
+
+ if (sanim && sanim->anim && ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
char fname[FILE_MAXFILE];
if (ed->proxy_dir[0] == 0)
BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
else
BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
- IMB_anim_get_fname(seq->anim, fname, FILE_MAXFILE);
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
BLI_path_append(dir, sizeof(dir), fname);
BLI_path_abs(name, G.main->name);
}
else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
}
- else if (seq->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
+ else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
char fname[FILE_MAXFILE];
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- IMB_anim_get_fname(seq->anim, fname, FILE_MAXFILE);
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
BLI_path_append(dir, sizeof(dir), fname);
}
else if (seq->type == SEQ_TYPE_IMAGE) {
@@ -1438,12 +1607,16 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
return false;
}
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && seq->anim &&
+ if (view_id > 0)
+ BLI_snprintf(suffix, sizeof(suffix), "_%zu", view_id);
+
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && sanim && sanim->anim &&
ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE)
{
BLI_join_dirfile(name, PROXY_MAXFILE,
dir, proxy->file);
BLI_path_abs(name, G.main->name);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", name, suffix);
return true;
}
@@ -1451,13 +1624,13 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
/* generate a separate proxy directory for each preview size */
if (seq->type == SEQ_TYPE_IMAGE) {
- BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir, render_size,
- BKE_sequencer_give_stripelem(seq, cfra)->name);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy%s", dir, render_size,
+ BKE_sequencer_give_stripelem(seq, cfra)->name, suffix);
frameno = 1;
}
else {
frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, render_size);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix);
}
BLI_path_abs(name, G.main->name);
@@ -1476,6 +1649,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
int render_size = context->preview_render_size;
StripProxy *proxy = seq->strip->proxy;
Editing *ed = context->scene->ed;
+ StripAnim *sanim;
if (!(seq->flag & SEQ_USE_PROXY)) {
return NULL;
@@ -1496,7 +1670,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
if (proxy->anim == NULL) {
- if (seq_proxy_get_fname(ed, seq, cfra, render_size, name) == 0) {
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
@@ -1506,14 +1680,15 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
return NULL;
}
- seq_open_anim_file(context->scene->ed, seq, true);
+ seq_open_anim_file(context->scene, seq, true);
+ sanim = seq->anims.first;
- frameno = IMB_anim_index_get_frame_index(seq->anim, proxy->tc, frameno);
+ frameno = IMB_anim_index_get_frame_index(sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno);
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
- if (seq_proxy_get_fname(ed, seq, cfra, render_size, name) == 0) {
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
@@ -1540,7 +1715,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
ImBuf *ibuf_tmp, *ibuf;
Editing *ed = context->scene->ed;
- if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name)) {
+ if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) {
return;
}
@@ -1581,44 +1756,130 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
IMB_freeImBuf(ibuf);
}
-SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list)
+/* returns whether the file this context would read from even exist, if not, don't create the context
+*/
+static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const size_t view_id)
+{
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ static char prefix[FILE_MAX];
+ static char *ext = NULL;
+ char str[FILE_MAX];
+
+ if (view_id == 0) {
+ char path[FILE_MAX];
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
+ seq->strip->stripdata->name);
+ BLI_path_abs(path, G.main->name);
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+ }
+
+ if (prefix[0] == '\0')
+ return view_id != 0;
+
+ seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX);
+
+ if (BLI_access(str, R_OK) == 0)
+ return false;
+ else
+ return view_id != 0;
+ }
+ return false;
+}
+
+/** This returns the maximum possible number of required contexts
+*/
+static size_t seq_proxy_context_count(Sequence *seq, Scene *scene)
+{
+ size_t num_views = 1;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE:
+ {
+ num_views = BLI_listbase_count(&seq->anims);
+ break;
+ }
+ case SEQ_TYPE_IMAGE:
+ {
+ switch (seq->views_format) {
+ case R_IMF_VIEWS_INDIVIDUAL:
+ num_views = BKE_scene_multiview_num_views_get(&scene->r);
+ break;
+ case R_IMF_VIEWS_STEREO_3D:
+ num_views = 2;
+ break;
+ case R_IMF_VIEWS_MULTIVIEW:
+ /* not supported at the moment */
+ /* pass through */
+ default:
+ num_views = 1;
+ }
+ break;
+ }
+ }
+
+ return num_views;
+}
+
+void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue)
{
SeqIndexBuildContext *context;
Sequence *nseq;
+ LinkData *link;
+ size_t i;
+ size_t num_files;
if (!seq->strip || !seq->strip->proxy) {
- return NULL;
+ return;
}
if (!(seq->flag & SEQ_USE_PROXY)) {
- return NULL;
+ return;
}
- context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+ num_files = seq_proxy_context_count(seq, scene);
+
+ for (i = 0; i < num_files; i++) {
+ if (seq_proxy_multiview_context_invalid(seq, scene, i))
+ continue;
+
+ context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+
+ nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0);
- nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0);
+ context->tc_flags = nseq->strip->proxy->build_tc_flags;
+ context->size_flags = nseq->strip->proxy->build_size_flags;
+ context->quality = nseq->strip->proxy->quality;
+ context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
- context->tc_flags = nseq->strip->proxy->build_tc_flags;
- context->size_flags = nseq->strip->proxy->build_size_flags;
- context->quality = nseq->strip->proxy->quality;
- context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
+ context->bmain = bmain;
+ context->scene = scene;
+ context->orig_seq = seq;
+ context->seq = nseq;
- context->bmain = bmain;
- context->scene = scene;
- context->orig_seq = seq;
- context->seq = nseq;
+ context->view_id = i; /* only for images */
- if (nseq->type == SEQ_TYPE_MOVIE) {
- seq_open_anim_file(scene->ed, nseq, true);
+ link = BLI_genericNodeN(context);
+ BLI_addtail(queue, link);
- if (nseq->anim) {
- context->index_context = IMB_anim_index_rebuild_context(nseq->anim,
- context->tc_flags, context->size_flags, context->quality,
- context->overwrite, file_list);
+ if (nseq->type == SEQ_TYPE_MOVIE) {
+ StripAnim *sanim;
+
+ seq_open_anim_file(scene, nseq, true);
+ sanim = BLI_findlink(&nseq->anims, i);
+
+ if (sanim->anim) {
+ context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
+ context->tc_flags, context->size_flags, context->quality,
+ context->overwrite, file_list);
+ }
}
}
-
- return context;
}
void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_update, float *progress)
@@ -1657,6 +1918,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
render_context.skip_cache = true;
render_context.is_proxy_render = true;
+ render_context.view_id = context->view_id;
for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
if (context->size_flags & IMB_PROXY_25) {
@@ -1683,8 +1945,14 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
{
if (context->index_context) {
- IMB_close_anim_proxies(context->seq->anim);
- IMB_close_anim_proxies(context->orig_seq->anim);
+ StripAnim *sanim;
+
+ for (sanim = context->seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
+
+ for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
+
IMB_anim_index_rebuild_finish(context->index_context, stop);
}
@@ -2429,6 +2697,234 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequenc
return out;
}
+static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
+{
+ ImBuf *ibuf = NULL;
+ char name[FILE_MAX];
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+ StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
+ int flag;
+
+ if (s_elem) {
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+ BLI_path_abs(name, G.main->name);
+ }
+
+ flag = IB_rect;
+ if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
+ flag |= IB_alphamode_premul;
+
+ if (!s_elem) {
+ /* don't do anything */
+ }
+ else if (is_multiview) {
+ size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
+ size_t totviews;
+ struct ImBuf **ibufs_arr;
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ int i;
+
+ if (totfiles > 1) {
+ BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
+ if (prefix[0] == '\0') {
+ goto monoview_image;
+ }
+ }
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+
+ if (prefix[0] == '\0') {
+ ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ }
+ else {
+ char str[FILE_MAX];
+ seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX);
+ ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ }
+
+ if (ibufs_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect)
+ imb_freerectImBuf(ibufs_arr[i]);
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0])
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i]) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+ if (ibuf) {
+ s_elem->orig_width = ibufs_arr[0]->x;
+ s_elem->orig_height = ibufs_arr[0]->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibufs_arr);
+ }
+ else {
+monoview_image:
+ if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect)
+ imb_freerectImBuf(ibuf);
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+ }
+ }
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
+{
+ ImBuf *ibuf = NULL;
+ StripAnim *sanim;
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+
+ /* load all the videos */
+ seq_open_anim_file(context->scene, seq, false);
+
+ if (is_multiview) {
+ ImBuf **ibuf_arr;
+ size_t totviews;
+ size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
+ int i;
+
+ if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1))
+ goto monoview_movie;
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) {
+ if (sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) {
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect)
+ imb_freerectImBuf(ibuf_arr[i]);
+ }
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (ibuf_arr[0]) {
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ }
+ else {
+ /* probably proxy hasn't been created yet */
+ MEM_freeN(ibuf_arr);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ if (ibuf_arr[i]) {
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
+ }
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibuf_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf_arr[i]);
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[context->view_id];
+ if (ibuf) {
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibuf_arr);
+ }
+ else {
+monoview_movie:
+ sanim = seq->anims.first;
+ if (sanim && sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf && proxy_size != IMB_PROXY_NONE) {
+ ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf) {
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+ }
+ }
+ return ibuf;
+}
+
static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence *seq, float nr)
{
ImBuf *ibuf = NULL;
@@ -2560,7 +3056,7 @@ static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq,
return seq_render_mask(context, seq->mask, nr, make_float);
}
-static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr)
+static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
{
ImBuf *ibuf = NULL;
float frame;
@@ -2658,6 +3154,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
char err_out[256] = "unknown";
int width = (scene->r.xsch * scene->r.size) / 100;
int height = (scene->r.ysch * scene->r.size) / 100;
+ const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
/* for old scened this can be uninitialized,
* should probably be added to do_versions at some point if the functionality stays */
@@ -2669,14 +3166,18 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
ibuf = sequencer_view3d_cb(scene, camera, width, height, IB_rect,
context->scene->r.seq_prev_type,
(context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0,
- use_gpencil, true, scene->r.alphamode, err_out);
+ use_gpencil, true, scene->r.alphamode, viewname, err_out);
if (ibuf == NULL) {
fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
}
}
else {
Render *re = RE_GetRender(scene->id.name);
- RenderResult rres;
+ size_t totviews = BKE_scene_multiview_num_views_get(&scene->r);
+ int i;
+ ImBuf **ibufs_arr;
+
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
/* XXX: this if can be removed when sequence preview rendering uses the job system
*
@@ -2696,27 +3197,51 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
G.is_rendering = is_rendering;
}
-
- RE_AcquireResultImage(re, &rres);
-
- if (rres.rectf) {
- ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
- memcpy(ibuf->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
- if (rres.rectz) {
- addzbuffloatImBuf(ibuf);
- memcpy(ibuf->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ RenderResult rres;
+
+ localcontext.view_id = i;
+
+ RE_AcquireResultImage(re, &rres, i);
+
+ if (rres.rectf) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
+ memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
+
+ if (rres.rectz) {
+ addzbuffloatImBuf(ibufs_arr[i]);
+ memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+ }
+
+ /* float buffers in the sequencer are not linear */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ }
+ else if (rres.rect32) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
+ memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
}
- /* float buffers in the sequencer are not linear */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+
+ RE_ReleaseResultImage(re);
}
- else if (rres.rect32) {
- ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
- memcpy(ibuf->rect, rres.rect32, 4 * rres.rectx * rres.recty);
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
}
-
- RE_ReleaseResultImage(re);
-
+ MEM_freeN(ibufs_arr);
+
// BIF_end_render_callbacks();
}
@@ -2743,7 +3268,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
float nr = give_stripelem_index(seq, cfra);
int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
bool use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
- char name[FILE_MAX];
switch (type) {
case SEQ_TYPE_META:
@@ -2802,64 +3326,14 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_IMAGE:
{
- StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
- int flag;
-
- if (s_elem) {
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
- BLI_path_abs(name, G.main->name);
- }
-
- flag = IB_rect;
- if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
- flag |= IB_alphamode_premul;
-
- if (s_elem && (ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect)
- imb_freerectImBuf(ibuf);
-
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
-
- s_elem->orig_width = ibuf->x;
- s_elem->orig_height = ibuf->y;
- }
+ ibuf = seq_render_image_strip(context, seq, nr, cfra);
+ copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
case SEQ_TYPE_MOVIE:
{
- seq_open_anim_file(context->scene->ed, seq, false);
-
- if (seq->anim) {
- IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
- IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
-
- ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- proxy_size);
-
- /* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf && proxy_size != IMB_PROXY_NONE) {
- ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
- }
- if (ibuf) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
-
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
- }
- }
+ ibuf = seq_render_movie_strip(context, seq, nr, cfra);
copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
@@ -2867,7 +3341,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_SCENE:
{
/* scene can be NULL after deletions */
- ibuf = seq_render_scene_strip(context, seq, nr);
+ ibuf = seq_render_scene_strip(context, seq, nr, cfra);
/* Scene strips update all animation, so we need to restore original state.*/
BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
@@ -3364,16 +3838,6 @@ ImBuf *BKE_sequencer_give_ibuf_threaded(const SeqRenderData *context, float cfra
return e ? e->ibuf : NULL;
}
-/* Functions to free imbuf and anim data on changes */
-
-static void free_anim_seq(Sequence *seq)
-{
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
-}
-
/* check whether sequence cur depends on seq */
bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
{
@@ -3425,15 +3889,11 @@ static void sequence_invalidate_cache(Scene *scene, Sequence *seq, bool invalida
/* invalidate cache for current sequence */
if (invalidate_self) {
- if (seq->anim) {
- /* Animation structure holds some buffers inside,
- * so for proper cache invalidation we need to
- * re-open the animation.
- */
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
-
+ /* Animation structure holds some buffers inside,
+ * so for proper cache invalidation we need to
+ * re-open the animation.
+ */
+ BKE_sequence_free_anim(seq);
BKE_sequencer_cache_cleanup_sequence(seq);
}
@@ -3480,7 +3940,7 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
if (seq->strip) {
if (seq->type == SEQ_TYPE_MOVIE) {
- free_anim_seq(seq);
+ BKE_sequence_free_anim(seq);
}
if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
@@ -3527,7 +3987,7 @@ static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *cha
if (free_imbuf) {
if (ibuf_change) {
if (seq->type == SEQ_TYPE_MOVIE)
- free_anim_seq(seq);
+ BKE_sequence_free_anim(seq);
if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
}
@@ -4415,6 +4875,8 @@ Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine)
seq->pitch = 1.0f;
seq->scene_sound = NULL;
+ seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
+
return seq;
}
@@ -4472,6 +4934,12 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
+ if (seq_load->stereo3d_format)
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+
+ seq->views_format = seq_load->views_format;
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
seq_load_apply(scene, seq, seq_load);
return seq;
@@ -4551,6 +5019,12 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
}
#endif // WITH_AUDASPACE
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ IMB_suffix_anim(anim, suffix);
+}
+
Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
Scene *scene = CTX_data_scene(C); /* only for sound */
@@ -4560,29 +5034,84 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
Strip *strip;
StripElem *se;
char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
-
- struct anim *an;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
+ size_t totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
+ struct anim **anim_arr;
+ int i;
BLI_strncpy(path, seq_load->path, sizeof(path));
BLI_path_abs(path, G.main->name);
- an = openanim(path, IB_rect, 0, colorspace);
+ anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
- if (an == NULL)
- return NULL;
+ if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ size_t j = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ char str[FILE_MAX];
+
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim_arr[j] = openanim(str, IB_rect, 0, colorspace);
+ seq_anim_add_suffix(scene, anim_arr[j], i);
+
+ if (anim_arr[j]) {
+ j++;
+ }
+ }
+
+ if (j == 0) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
+
+ if (anim_arr[0] == NULL) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ }
seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
+
+ /* multiview settings */
+ if (seq_load->stereo3d_format) {
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+ seq->views_format = seq_load->views_format;
+ }
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
seq->type = SEQ_TYPE_MOVIE;
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
- seq->anim = an;
- seq->anim_preseek = IMB_anim_get_preseek(an);
+ for (i = 0; i < totfiles; i++) {
+ if (anim_arr[i]) {
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim_arr[i];
+ }
+ else {
+ break;
+ }
+ }
+
+ seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
/* basic defaults */
seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
+ seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
strip->us = 1;
BLI_strncpy(seq->strip->colorspace_settings.name, colorspace, sizeof(seq->strip->colorspace_settings.name));
@@ -4610,6 +5139,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
/* can be NULL */
seq_load_apply(scene, seq, seq_load);
+ MEM_freeN(anim_arr);
return seq;
}
@@ -4621,6 +5151,8 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
seq->tmp = seqn;
seqn->strip = MEM_dupallocN(seq->strip);
+ seqn->stereo3d_format = MEM_dupallocN(seq->stereo3d_format);
+
/* XXX: add F-Curve duplication stuff? */
if (seq->strip->crop) {
@@ -4667,7 +5199,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
else if (seq->type == SEQ_TYPE_MOVIE) {
seqn->strip->stripdata =
MEM_dupallocN(seq->strip->stripdata);
- seqn->anim = NULL;
+ BLI_listbase_clear(&seqn->anims);
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
seqn->strip->stripdata =
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index a86ffacfdbd..cec455e01b9 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -50,26 +50,34 @@
/* ********************** general blender movie support ***************************** */
-static int start_stub(Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
- ReportList *UNUSED(reports), bool UNUSED(preview))
+static int start_stub(void *UNUSED(context_v), Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
+ ReportList *UNUSED(reports), bool UNUSED(preview), const char *UNUSED(suffix))
{ return 0; }
-static void end_stub(void)
+static void end_stub(void *UNUSED(context_v))
{}
-static int append_stub(RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
- int UNUSED(rectx), int UNUSED(recty), ReportList *UNUSED(reports))
+static int append_stub(void *UNUSED(context_v), RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
+ int UNUSED(rectx), int UNUSED(recty), const char *UNUSED(suffix), ReportList *UNUSED(reports))
{ return 0; }
+static void *context_create_stub(void)
+{ return NULL; }
+
+static void context_free_stub(void *UNUSED(context_v))
+{}
+
#ifdef WITH_AVI
# include "AVI_avi.h"
/* callbacks */
-static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview);
-static void end_avi(void);
-static int append_avi(RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, ReportList *reports);
-static void filepath_avi(char *string, RenderData *rd, bool preview);
+static int start_avi(void *context_v, Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix);
+static void end_avi(void *context_v);
+static int append_avi(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, ReportList *reports);
+static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix);
+static void *context_create_avi(void);
+static void context_free_avi(void *context_v);
#endif /* WITH_AVI */
#ifdef WITH_QUICKTIME
@@ -93,13 +101,17 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.end_movie = end_stub;
mh.get_next_frame = NULL;
mh.get_movie_path = NULL;
-
+ mh.context_create = context_create_stub;
+ mh.context_free = context_free_stub;
+
/* set the default handle, as builtin */
#ifdef WITH_AVI
mh.start_movie = start_avi;
mh.append_movie = append_avi;
mh.end_movie = end_avi;
mh.get_movie_path = filepath_avi;
+ mh.context_create = context_create_avi;
+ mh.context_free = context_free_avi;
#endif
/* do the platform specific handles */
@@ -109,6 +121,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = append_qt;
mh.end_movie = end_qt;
mh.get_movie_path = filepath_qt;
+ mh.context_create = context_create_qt;
+ mh.context_free = context_free_qt;
}
#endif
#ifdef WITH_FFMPEG
@@ -117,6 +131,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
mh.get_movie_path = BKE_ffmpeg_filepath_get;
+ mh.context_create = BKE_ffmpeg_context_create;
+ mh.context_free = BKE_ffmpeg_context_free;
}
#endif
#ifdef WITH_FRAMESERVER
@@ -125,6 +141,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_frameserver_append;
mh.end_movie = BKE_frameserver_end;
mh.get_next_frame = BKE_frameserver_loop;
+ mh.context_create = BKE_frameserver_context_create;
+ mh.context_free = BKE_frameserver_context_free;
}
#endif
@@ -137,9 +155,7 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#ifdef WITH_AVI
-static AviMovie *avi = NULL;
-
-static void filepath_avi(char *string, RenderData *rd, bool preview)
+static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix)
{
int sfra, efra;
@@ -170,27 +186,27 @@ static void filepath_avi(char *string, RenderData *rd, bool preview)
BLI_path_frame_range(string, sfra, efra, 4);
}
}
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
}
-static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview)
+static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int rectx, int recty,
+ ReportList *reports, bool preview, const char *suffix)
{
int x, y;
char name[256];
AviFormat format;
int quality;
double framerate;
-
- (void)scene; /* unused */
-
- filepath_avi(name, rd, preview);
+ AviMovie *avi = context_v;
+
+ filepath_avi(name, rd, preview, suffix);
x = rectx;
y = recty;
quality = rd->im_format.quality;
framerate = (double) rd->frs_sec / (double) rd->frs_sec_base;
-
- avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG) format = AVI_FORMAT_AVI_RGB;
else format = AVI_FORMAT_MJPEG;
@@ -216,12 +232,13 @@ static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportL
return 1;
}
-static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
- int rectx, int recty, ReportList *UNUSED(reports))
+static int append_avi(void *context_v, RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
unsigned int *rt1, *rt2, *rectot;
int x, y;
char *cp, rt;
+ AviMovie *avi = context_v;
if (avi == NULL)
return 0;
@@ -252,22 +269,37 @@ static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *p
return 1;
}
-static void end_avi(void)
+static void end_avi(void *context_v)
{
+ AviMovie *avi = context_v;
+
if (avi == NULL) return;
AVI_close_compress(avi);
- MEM_freeN(avi);
- avi = NULL;
}
+
+static void *context_create_avi(void)
+{
+ AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
+ return avi;
+}
+
+static void context_free_avi(void *context_v)
+{
+ AviMovie *avi = context_v;
+ if (avi) {
+ MEM_freeN(avi);
+ }
+}
+
#endif /* WITH_AVI */
/* similar to BKE_image_path_from_imformat() */
-void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview)
+void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
if (mh->get_movie_path)
- mh->get_movie_path(string, rd, preview);
+ mh->get_movie_path(string, rd, preview, suffix);
else
string[0] = '\0';
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 0717369cde8..af71f19c226 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -61,36 +61,38 @@
#include "ffmpeg_compat.h"
-static int ffmpeg_type = 0;
-static int ffmpeg_codec = AV_CODEC_ID_MPEG4;
-static int ffmpeg_audio_codec = AV_CODEC_ID_NONE;
-static int ffmpeg_video_bitrate = 1150;
-static int ffmpeg_audio_bitrate = 128;
-static int ffmpeg_gop_size = 12;
-static int ffmpeg_autosplit = 0;
-static int ffmpeg_autosplit_count = 0;
-static bool ffmpeg_preview = false;
-
-static AVFormatContext *outfile = 0;
-static AVStream *video_stream = 0;
-static AVStream *audio_stream = 0;
-static AVFrame *current_frame = 0;
-static struct SwsContext *img_convert_ctx = 0;
-
-static uint8_t *audio_input_buffer = 0;
-static uint8_t *audio_deinterleave_buffer = 0;
-static int audio_input_samples = 0;
+typedef struct FFMpegContext {
+ int ffmpeg_type;
+ int ffmpeg_codec;
+ int ffmpeg_audio_codec;
+ int ffmpeg_video_bitrate;
+ int ffmpeg_audio_bitrate;
+ int ffmpeg_gop_size;
+ int ffmpeg_autosplit;
+ int ffmpeg_autosplit_count;
+ bool ffmpeg_preview;
+
+ AVFormatContext *outfile;
+ AVStream *video_stream;
+ AVStream *audio_stream;
+ AVFrame *current_frame;
+ struct SwsContext *img_convert_ctx;
+
+ uint8_t *audio_input_buffer;
+ uint8_t *audio_deinterleave_buffer;
+ int audio_input_samples;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
-static uint8_t *audio_output_buffer = 0;
-static int audio_outbuf_size = 0;
+ uint8_t *audio_output_buffer;
+ int audio_outbuf_size;
#endif
-static double audio_time = 0.0f;
-static bool audio_deinterleave = false;
-static int audio_sample_size = 0;
+ double audio_time;
+ bool audio_deinterleave;
+ int audio_sample_size;
#ifdef WITH_AUDASPACE
-static AUD_Device *audio_mixdown_device = 0;
+ AUD_Device *audio_mixdown_device;
#endif
+} FFMpegContext;
#define FFMPEG_AUTOSPLIT_SIZE 2000000000
@@ -99,6 +101,7 @@ static AUD_Device *audio_mixdown_device = 0;
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value);
static void ffmpeg_set_expert_options(RenderData *rd);
+static void ffmpeg_filepath_get(FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix);
/* Delete a picture buffer */
@@ -117,50 +120,50 @@ static int request_float_audio_buffer(int codec_id)
}
#ifdef WITH_AUDASPACE
-static int write_audio_frame(void)
+static int write_audio_frame(FFMpegContext *context)
{
AVCodecContext *c = NULL;
AVPacket pkt;
AVFrame *frame = NULL;
int got_output = 0;
- c = audio_stream->codec;
+ c = context->audio_stream->codec;
av_init_packet(&pkt);
pkt.size = 0;
pkt.data = NULL;
- AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
- audio_time += (double) audio_input_samples / (double) c->sample_rate;
+ AUD_readDevice(context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
+ context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate;
#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
frame = avcodec_alloc_frame();
avcodec_get_frame_defaults(frame);
- frame->pts = audio_time / av_q2d(c->time_base);
- frame->nb_samples = audio_input_samples;
+ frame->pts = context->audio_time / av_q2d(c->time_base);
+ frame->nb_samples = context->audio_input_samples;
frame->format = c->sample_fmt;
#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
frame->channel_layout = c->channel_layout;
#endif
- if (audio_deinterleave) {
+ if (context->audio_deinterleave) {
int channel, i;
uint8_t *temp;
for (channel = 0; channel < c->channels; channel++) {
for (i = 0; i < frame->nb_samples; i++) {
- memcpy(audio_deinterleave_buffer + (i + channel * frame->nb_samples) * audio_sample_size,
- audio_input_buffer + (c->channels * i + channel) * audio_sample_size, audio_sample_size);
+ memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size,
+ context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size);
}
}
- temp = audio_deinterleave_buffer;
- audio_deinterleave_buffer = audio_input_buffer;
- audio_input_buffer = temp;
+ temp = context->audio_deinterleave_buffer;
+ context->audio_deinterleave_buffer = context->audio_input_buffer;
+ context->audio_input_buffer = temp;
}
- avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, audio_input_buffer,
- audio_input_samples * c->channels * audio_sample_size, 1);
+ avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, context->audio_input_buffer,
+ context->audio_input_samples * c->channels * context->audio_sample_size, 1);
if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
// XXX error("Error writing audio packet");
@@ -172,30 +175,30 @@ static int write_audio_frame(void)
return 0;
}
#else
- pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer);
+ pkt.size = avcodec_encode_audio(c, context->audio_output_buffer, context->audio_outbuf_size, (short *) context->audio_input_buffer);
if (pkt.size < 0) {
// XXX error("Error writing audio packet");
return -1;
}
- pkt.data = audio_output_buffer;
+ pkt.data = context->audio_output_buffer;
got_output = 1;
#endif
if (got_output) {
if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(pkt.pts, c->time_base, audio_stream->time_base);
+ pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts = av_rescale_q(pkt.dts, c->time_base, audio_stream->time_base);
+ pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
if (pkt.duration > 0)
- pkt.duration = av_rescale_q(pkt.duration, c->time_base, audio_stream->time_base);
+ pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
- pkt.stream_index = audio_stream->index;
+ pkt.stream_index = context->audio_stream->index;
pkt.flags |= AV_PKT_FLAG_KEY;
- if (av_interleaved_write_frame(outfile, &pkt) != 0) {
+ if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
if (frame)
avcodec_free_frame(&frame);
@@ -302,11 +305,11 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
-static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
+static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
{
int got_output;
int ret, success = 1;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
AVPacket packet = { 0 };
av_init_packet(&packet);
@@ -321,22 +324,22 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
if (ret >= 0 && got_output) {
if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int)packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int)packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
- packet.stream_index = video_stream->index;
- ret = av_interleaved_write_frame(outfile, &packet);
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
success = (ret == 0);
}
else if (ret < 0) {
@@ -350,11 +353,11 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
}
/* read and encode a frame of audio from the buffer */
-static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
+static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, ReportList *reports)
{
uint8_t *rendered_frame;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
int width = c->width;
int height = c->height;
AVFrame *rgb_frame;
@@ -367,7 +370,7 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
}
else {
- rgb_frame = current_frame;
+ rgb_frame = context->current_frame;
}
rendered_frame = pixels;
@@ -411,17 +414,17 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
if (c->pix_fmt != PIX_FMT_BGR32) {
- sws_scale(img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
+ sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
rgb_frame->linesize, 0, c->height,
- current_frame->data, current_frame->linesize);
+ context->current_frame->data, context->current_frame->linesize);
delete_picture(rgb_frame);
}
- current_frame->format = PIX_FMT_BGR32;
- current_frame->width = width;
- current_frame->height = height;
+ context->current_frame->format = PIX_FMT_BGR32;
+ context->current_frame->width = width;
+ context->current_frame->height = height;
- return current_frame;
+ return context->current_frame;
}
static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary)
@@ -516,7 +519,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
/* prepare a video stream for the output file */
-static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext *of,
+static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of,
int rectx, int recty, char *error, int error_size)
{
AVStream *st;
@@ -542,7 +545,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->height = recty;
/* FIXME: Really bad hack (tm) for NTSC support */
- if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
+ if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
c->time_base.den = 2997;
c->time_base.num = 100;
}
@@ -555,8 +558,8 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->time_base.num = ((double) rd->frs_sec_base) * 100000;
}
- c->gop_size = ffmpeg_gop_size;
- c->bit_rate = ffmpeg_video_bitrate * 1000;
+ c->gop_size = context->ffmpeg_gop_size;
+ c->bit_rate = context->ffmpeg_video_bitrate * 1000;
c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
@@ -585,7 +588,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->pix_fmt = PIX_FMT_YUV422P;
}
- if (ffmpeg_type == FFMPEG_XVID) {
+ if (context->ffmpeg_type == FFMPEG_XVID) {
/* arghhhh ... */
c->pix_fmt = PIX_FMT_YUV420P;
c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
@@ -655,14 +658,14 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
}
av_dict_free(&opts);
- current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
+ context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
- img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
+ context->img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
NULL, NULL, NULL);
return st;
}
-static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
+static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
{
AVStream *st;
AVCodecContext *c;
@@ -680,7 +683,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
c->codec_type = AVMEDIA_TYPE_AUDIO;
c->sample_rate = rd->ffcodecdata.audio_mixrate;
- c->bit_rate = ffmpeg_audio_bitrate * 1000;
+ c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->channels = rd->ffcodecdata.audio_channels;
@@ -747,35 +750,35 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
st->codec->time_base.den = st->codec->sample_rate;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- audio_outbuf_size = FF_MIN_BUFFER_SIZE;
+ context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
#endif
if (c->frame_size == 0)
// used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
// not sure if that is needed anymore, so let's try out if there are any
// complaints regarding some ffmpeg versions users might have
- audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
+ context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
else {
- audio_input_samples = c->frame_size;
+ context->audio_input_samples = c->frame_size;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size)
- audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
+ if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size)
+ context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
#endif
}
- audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
+ context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
- audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
+ context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
- audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
+ context->audio_input_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size);
+ context->audio_output_buffer = (uint8_t *) av_malloc(context->audio_outbuf_size);
#endif
- if (audio_deinterleave)
- audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
+ if (context->audio_deinterleave)
+ context->audio_deinterleave_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
- audio_time = 0.0f;
+ context->audio_time = 0.0f;
return st;
}
@@ -799,7 +802,7 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va
av_dict_set(dict, key, buffer, 0);
}
-static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports)
+static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports)
{
/* Handle to the output file */
AVFormatContext *of;
@@ -808,26 +811,26 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
char name[256], error[1024];
const char **exts;
- ffmpeg_type = rd->ffcodecdata.type;
- ffmpeg_codec = rd->ffcodecdata.codec;
- ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
- ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
- ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
- ffmpeg_gop_size = rd->ffcodecdata.gop_size;
- ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
-
+ context->ffmpeg_type = rd->ffcodecdata.type;
+ context->ffmpeg_codec = rd->ffcodecdata.codec;
+ context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
+ context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
+ context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
+ context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
+ context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
+
/* Determine the correct filename */
- BKE_ffmpeg_filepath_get(name, rd, ffmpeg_preview);
+ ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
PRINT("Starting output to %s(ffmpeg)...\n"
" Using type=%d, codec=%d, audio_codec=%d,\n"
" video_bitrate=%d, audio_bitrate=%d,\n"
" gop_size=%d, autosplit=%d\n"
" render width=%d, render height=%d\n",
- name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
- ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
- ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty);
+ name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec,
+ context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate,
+ context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty);
- exts = get_file_extensions(ffmpeg_type);
+ exts = get_file_extensions(context->ffmpeg_type);
if (!exts) {
BKE_report(reports, RPT_ERROR, "No valid formats found");
return 0;
@@ -846,7 +849,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->oformat = fmt;
of->packet_size = rd->ffcodecdata.mux_packet_size;
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
}
else {
@@ -857,15 +860,15 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->max_delay = (int)(0.7 * AV_TIME_BASE);
- fmt->audio_codec = ffmpeg_audio_codec;
+ fmt->audio_codec = context->ffmpeg_audio_codec;
BLI_strncpy(of->filename, name, sizeof(of->filename));
/* set the codec to the user's selection */
- switch (ffmpeg_type) {
+ switch (context->ffmpeg_type) {
case FFMPEG_AVI:
case FFMPEG_MOV:
case FFMPEG_MKV:
- fmt->video_codec = ffmpeg_codec;
+ fmt->video_codec = context->ffmpeg_codec;
break;
case FFMPEG_OGG:
fmt->video_codec = AV_CODEC_ID_THEORA;
@@ -908,9 +911,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
- if (ffmpeg_type == FFMPEG_DV) {
+ if (context->ffmpeg_type == FFMPEG_DV) {
fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
av_dict_free(&opts);
return 0;
@@ -918,9 +921,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
if (fmt->video_codec != AV_CODEC_ID_NONE) {
- video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
- PRINT("alloc video stream %p\n", video_stream);
- if (!video_stream) {
+ context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
+ PRINT("alloc video stream %p\n", context->video_stream);
+ if (!context->video_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@@ -931,9 +934,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
- audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of, error, sizeof(error));
- if (!audio_stream) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error));
+ if (!context->audio_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@@ -956,7 +959,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
return 0;
}
- outfile = of;
+ context->outfile = of;
av_dump_format(of, 0, name, 1);
av_dict_free(&opts);
@@ -980,11 +983,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
* parameter.
* </p>
*/
-static void flush_ffmpeg(void)
+static void flush_ffmpeg(FFMpegContext *context)
{
int ret = 0;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
/* get the delayed frames */
while (1) {
int got_output;
@@ -1000,28 +1003,28 @@ static void flush_ffmpeg(void)
break;
}
if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int) packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int) packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
- packet.stream_index = video_stream->index;
- ret = av_interleaved_write_frame(outfile, &packet);
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
if (ret != 0) {
fprintf(stderr, "Error writing delayed frame %d\n", ret);
break;
}
}
- avcodec_flush_buffers(video_stream->codec);
+ avcodec_flush_buffers(context->video_stream->codec);
}
/* **********************************************************************
@@ -1029,7 +1032,7 @@ static void flush_ffmpeg(void)
* ********************************************************************** */
/* Get the output filename-- similar to the other output formats */
-void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview)
+static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix)
{
char autosplit[20];
@@ -1056,7 +1059,9 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview)
autosplit[0] = 0;
if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
- sprintf(autosplit, "_%03d", ffmpeg_autosplit_count);
+ if (context) {
+ sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count);
+ }
}
if (rd->scemode & R_EXTENSION) {
@@ -1086,19 +1091,28 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview)
strcat(string, autosplit);
}
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
}
-int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview)
+void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
+{
+ ffmpeg_filepath_get(NULL, string, rd, preview, suffix);
+}
+
+int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int rectx, int recty,
+ ReportList *reports, bool preview, const char *suffix)
{
int success;
+ FFMpegContext *context = context_v;
- ffmpeg_autosplit_count = 0;
- ffmpeg_preview = preview;
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = preview;
- success = start_ffmpeg_impl(rd, rectx, recty, reports);
+ success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
#ifdef WITH_AUDASPACE
- if (audio_stream) {
- AVCodecContext *c = audio_stream->codec;
+ if (context->audio_stream) {
+ AVCodecContext *c = context->audio_stream->codec;
AUD_DeviceSpecs specs;
specs.channels = c->channels;
@@ -1123,7 +1137,7 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
}
specs.rate = rd->ffcodecdata.audio_mixrate;
- audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
+ context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
#ifdef FFMPEG_CODEC_TIME_BASE
c->time_base.den = specs.rate;
c->time_base.num = 1;
@@ -1133,16 +1147,16 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
return success;
}
-static void end_ffmpeg_impl(int is_autosplit);
+static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit);
#ifdef WITH_AUDASPACE
-static void write_audio_frames(double to_pts)
+static void write_audio_frames(FFMpegContext *context, double to_pts)
{
int finished = 0;
- while (audio_stream && !finished) {
- if ((audio_time >= to_pts) ||
- (write_audio_frame()))
+ while (context->audio_stream && !finished) {
+ if ((context->audio_time >= to_pts) ||
+ (write_audio_frame(context)))
{
finished = 1;
}
@@ -1150,8 +1164,10 @@ static void write_audio_frames(double to_pts)
}
#endif
-int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports)
+int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, ReportList *reports)
{
+ FFMpegContext *context = context_v;
AVFrame *avframe;
int success = 1;
@@ -1160,111 +1176,112 @@ int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, i
/* why is this done before writing the video frame and again at end_ffmpeg? */
// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
- if (video_stream) {
- avframe = generate_video_frame((unsigned char *) pixels, reports);
- success = (avframe && write_video_frame(rd, frame - start_frame, avframe, reports));
+ if (context->video_stream) {
+ avframe = generate_video_frame(context, (unsigned char *) pixels, reports);
+ success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
- if (ffmpeg_autosplit) {
- if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
- end_ffmpeg_impl(true);
- ffmpeg_autosplit_count++;
- success &= start_ffmpeg_impl(rd, rectx, recty, reports);
+ if (context->ffmpeg_autosplit) {
+ if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
+ end_ffmpeg_impl(context, true);
+ context->ffmpeg_autosplit_count++;
+ success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
}
}
}
#ifdef WITH_AUDASPACE
- write_audio_frames((frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
+ write_audio_frames(context, (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
#endif
return success;
}
-static void end_ffmpeg_impl(int is_autosplit)
+static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
unsigned int i;
PRINT("Closing ffmpeg...\n");
#if 0
- if (audio_stream) { /* SEE UPPER */
- write_audio_frames();
+ if (context->audio_stream) { /* SEE UPPER */
+ write_audio_frames(context);
}
#endif
#ifdef WITH_AUDASPACE
if (is_autosplit == false) {
- if (audio_mixdown_device) {
- AUD_closeReadDevice(audio_mixdown_device);
- audio_mixdown_device = 0;
+ if (context->audio_mixdown_device) {
+ AUD_closeReadDevice(context->audio_mixdown_device);
+ context->audio_mixdown_device = 0;
}
}
#endif
- if (video_stream && video_stream->codec) {
+ if (context->video_stream && context->video_stream->codec) {
PRINT("Flushing delayed frames...\n");
- flush_ffmpeg();
+ flush_ffmpeg(context);
}
- if (outfile) {
- av_write_trailer(outfile);
+ if (context->outfile) {
+ av_write_trailer(context->outfile);
}
/* Close the video codec */
- if (video_stream && video_stream->codec) {
- avcodec_close(video_stream->codec);
- PRINT("zero video stream %p\n", video_stream);
- video_stream = 0;
+ if (context->video_stream && context->video_stream->codec) {
+ avcodec_close(context->video_stream->codec);
+ PRINT("zero video stream %p\n", context->video_stream);
+ context->video_stream = 0;
}
/* Close the output file */
- if (outfile) {
- for (i = 0; i < outfile->nb_streams; i++) {
- if (&outfile->streams[i]) {
- av_freep(&outfile->streams[i]);
+ if (context->outfile) {
+ for (i = 0; i < context->outfile->nb_streams; i++) {
+ if (&context->outfile->streams[i]) {
+ av_freep(&context->outfile->streams[i]);
}
}
}
/* free the temp buffer */
- if (current_frame) {
- delete_picture(current_frame);
- current_frame = 0;
+ if (context->current_frame) {
+ delete_picture(context->current_frame);
+ context->current_frame = 0;
}
- if (outfile && outfile->oformat) {
- if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
- avio_close(outfile->pb);
+ if (context->outfile && context->outfile->oformat) {
+ if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
+ avio_close(context->outfile->pb);
}
}
- if (outfile) {
- av_free(outfile);
- outfile = 0;
+ if (context->outfile) {
+ av_free(context->outfile);
+ context->outfile = 0;
}
- if (audio_input_buffer) {
- av_free(audio_input_buffer);
- audio_input_buffer = 0;
+ if (context->audio_input_buffer) {
+ av_free(context->audio_input_buffer);
+ context->audio_input_buffer = 0;
}
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (audio_output_buffer) {
- av_free(audio_output_buffer);
- audio_output_buffer = 0;
+ if (context->audio_output_buffer) {
+ av_free(context->audio_output_buffer);
+ context->audio_output_buffer = 0;
}
#endif
- if (audio_deinterleave_buffer) {
- av_free(audio_deinterleave_buffer);
- audio_deinterleave_buffer = 0;
+ if (context->audio_deinterleave_buffer) {
+ av_free(context->audio_deinterleave_buffer);
+ context->audio_deinterleave_buffer = 0;
}
- if (img_convert_ctx) {
- sws_freeContext(img_convert_ctx);
- img_convert_ctx = 0;
+ if (context->img_convert_ctx) {
+ sws_freeContext(context->img_convert_ctx);
+ context->img_convert_ctx = 0;
}
}
-void BKE_ffmpeg_end(void)
+void BKE_ffmpeg_end(void *context_v)
{
- end_ffmpeg_impl(false);
+ FFMpegContext *context = context_v;
+ end_ffmpeg_impl(context, false);
}
/* properties */
@@ -1658,4 +1675,31 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
return false;
}
-#endif
+void *BKE_ffmpeg_context_create(void)
+{
+ FFMpegContext *context;
+
+ /* new ffmpeg data struct */
+ context = MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context");
+
+ context->ffmpeg_codec = AV_CODEC_ID_MPEG4;
+ context->ffmpeg_audio_codec = AV_CODEC_ID_NONE;
+ context->ffmpeg_video_bitrate = 1150;
+ context->ffmpeg_audio_bitrate = 128;
+ context->ffmpeg_gop_size = 12;
+ context->ffmpeg_autosplit = 0;
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = false;
+
+ return context;
+}
+
+void BKE_ffmpeg_context_free(void *context_v)
+{
+ FFMpegContext *context = context_v;
+ if (context) {
+ MEM_freeN(context);
+ }
+}
+
+#endif /* WITH_FFMPEG */
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
index 9cac86d62bd..ba58038bbd8 100644
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ b/source/blender/blenkernel/intern/writeframeserver.c
@@ -66,12 +66,15 @@
#include "BKE_report.h"
#include "DNA_scene_types.h"
+#include "MEM_guardedalloc.h"
-static int sock;
-static int connsock;
-static int write_ppm;
-static int render_width;
-static int render_height;
+typedef struct FrameserverContext {
+ int sock;
+ int connsock;
+ int write_ppm;
+ int render_width;
+ int render_height;
+} FrameserverContext;
#if defined(_WIN32)
@@ -110,10 +113,11 @@ static int closesocket(int fd)
}
#endif
-int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview))
+int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix))
{
struct sockaddr_in addr;
int arg = 1;
+ FrameserverContext *context = context_v;
(void)scene; /* unused */
@@ -122,33 +126,33 @@ int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx
return 0;
}
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot open socket");
return 0;
}
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
+ setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
addr.sin_family = AF_INET;
addr.sin_port = htons(U.frameserverport);
addr.sin_addr.s_addr = INADDR_ANY;
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot bind to socket");
return 0;
}
- if (listen(sock, SOMAXCONN) < 0) {
+ if (listen(context->sock, SOMAXCONN) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog");
return 0;
}
- connsock = -1;
+ context->connsock = -1;
- render_width = rectx;
- render_height = recty;
+ context->render_width = rectx;
+ context->render_height = recty;
return 1;
}
@@ -177,7 +181,7 @@ static char good_bye[] =
"<body><pre>\n"
"Render stopped. Goodbye</pre></body></html>";
-static int safe_write(char *s, int tosend)
+static int safe_write(const int connsock, char *s, int tosend)
{
int total = tosend;
do {
@@ -192,12 +196,12 @@ static int safe_write(char *s, int tosend)
return total;
}
-static int safe_puts(char *s)
+static int safe_puts(const int connsock, char *s)
{
- return safe_write(s, strlen(s));
+ return safe_write(connsock, s, strlen(s));
}
-static int handle_request(RenderData *rd, char *req)
+static int handle_request(FrameserverContext *context, RenderData *rd, char *req)
{
char *p;
char *path;
@@ -214,16 +218,16 @@ static int handle_request(RenderData *rd, char *req)
*p = 0;
- if (STREQ(path, "/index.html") || STREQ(path, "/")) {
- safe_puts(index_page);
+ if (STREQ(path, "/index.html") || strcmp(path, "/")) {
+ safe_puts(context->connsock, index_page);
return -1;
}
- write_ppm = 0;
+ context->write_ppm = 0;
pathlen = strlen(path);
if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
- write_ppm = 1;
+ context->write_ppm = 1;
return atoi(path + 12);
}
if (STREQ(path, "/info.txt")) {
@@ -241,24 +245,24 @@ static int handle_request(RenderData *rd, char *req)
"ratescale %d\n",
rd->sfra,
rd->efra,
- render_width,
- render_height,
+ context->render_width,
+ context->render_height,
rd->frs_sec,
1
);
- safe_puts(buf);
+ safe_puts(context->connsock, buf);
return -1;
}
if (STREQ(path, "/close.txt")) {
- safe_puts(good_bye);
+ safe_puts(context->connsock, good_bye);
G.is_break = true; /* Abort render */
return -1;
}
return -1;
}
-int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
+int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports))
{
fd_set readfds;
struct timeval tv;
@@ -271,18 +275,20 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
#endif
char buf[4096];
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ FrameserverContext *context = context_v;
+
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&readfds);
- FD_SET(sock, &readfds);
+ FD_SET(context->sock, &readfds);
- rval = select(sock + 1, &readfds, NULL, NULL, &tv);
+ rval = select(context->sock + 1, &readfds, NULL, NULL, &tv);
if (rval < 0) {
return -1;
}
@@ -293,19 +299,19 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
socklen = sizeof(addr);
- if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) {
+ if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) {
return -1;
}
FD_ZERO(&readfds);
- FD_SET(connsock, &readfds);
+ FD_SET(context->connsock, &readfds);
for (;;) {
/* give 10 seconds for telnet testing... */
tv.tv_sec = 10;
tv.tv_usec = 0;
- rval = select(connsock + 1, &readfds, NULL, NULL, &tv);
+ rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv);
if (rval > 0) {
break;
}
@@ -319,7 +325,7 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
}
}
- len = recv(connsock, buf, sizeof(buf) - 1, 0);
+ len = recv(context->connsock, buf, sizeof(buf) - 1, 0);
if (len < 0) {
return -1;
@@ -327,13 +333,13 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
buf[len] = 0;
- return handle_request(rd, buf);
+ return handle_request(context, rd, buf);
}
-static void serve_ppm(int *pixels, int rectx, int recty)
+static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty)
{
unsigned char *rendered_frame;
- unsigned char *row = (unsigned char *) malloc(render_width * 3);
+ unsigned char *row = (unsigned char *) malloc(context->render_width * 3);
int y;
char header[1024];
@@ -348,7 +354,7 @@ static void serve_ppm(int *pixels, int rectx, int recty)
"255\n",
rectx, recty);
- safe_puts(header);
+ safe_puts(context->connsock, header);
rendered_frame = (unsigned char *)pixels;
@@ -364,36 +370,54 @@ static void serve_ppm(int *pixels, int rectx, int recty)
target += 3;
src += 4;
}
- safe_write((char *)row, 3 * rectx);
+ safe_write(context->connsock, (char *)row, 3 * rectx);
}
free(row);
- closesocket(connsock);
- connsock = -1;
+ closesocket(context->connsock);
+ context->connsock = -1;
}
-int BKE_frameserver_append(RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
- int rectx, int recty, ReportList *UNUSED(reports))
+int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
+ int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
+ FrameserverContext *context = context_v;
+
fprintf(stderr, "Serving frame: %d\n", frame);
- if (write_ppm) {
- serve_ppm(pixels, rectx, recty);
+ if (context->write_ppm) {
+ serve_ppm(context, pixels, rectx, recty);
}
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
return 1;
}
-void BKE_frameserver_end(void)
+void BKE_frameserver_end(void *context_v)
{
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ FrameserverContext *context = context_v;
+
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
- closesocket(sock);
+ closesocket(context->sock);
shutdown_socket_system();
}
+void *BKE_frameserver_context_create(void)
+{
+ FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context");
+ return context;
+}
+
+void BKE_frameserver_context_free(void *context_v)
+{
+ FrameserverContext *context = context_v;
+ if (context) {
+ MEM_freeN(context);
+ }
+}
+
#endif /* WITH_FRAMESERVER */