diff options
author | Sybren A. Stüvel <sybren@stuvel.eu> | 2018-04-05 17:58:41 +0300 |
---|---|---|
committer | Sybren A. Stüvel <sybren@stuvel.eu> | 2018-04-05 17:58:41 +0300 |
commit | 57329304b061efe756e3a4ce1b828e9a7c7f7030 (patch) | |
tree | c4a3f9ec01c09314fac7bcb99b437bf0920d19a3 /source/blender | |
parent | 3eaf77fdd34bd9517b650cabde3574361bdc8d21 (diff) | |
parent | ea0e2f9bd3849b73a29ef1805988fdb0484bc9d4 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source/blender')
25 files changed, 311 insertions, 130 deletions
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 57459412efc..1af123759e6 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -67,6 +67,11 @@ void BKE_image_init(struct Image *image); typedef void (StampCallback)(void *data, const char *propname, char *propvalue, int len); void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr, bool allocate_only); +/** + * Fills in the static stamp data (i.e. everything except things that can change per frame). + * The caller is responsible for freeing the allocated memory. + */ +struct StampData *BKE_stamp_info_from_scene_static(struct Scene *scene); void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf); void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf); void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index d421d780343..ef48b3c1a45 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -46,6 +46,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#include "IMB_metadata.h" #ifdef WITH_OPENEXR # include "intern/openexr/openexr_multi.h" @@ -1623,6 +1624,7 @@ typedef struct StampData { char marker[512]; char time[512]; char frame[512]; + char frame_range[512]; char camera[STAMP_NAME_SIZE]; char cameralens[STAMP_NAME_SIZE]; char scene[STAMP_NAME_SIZE]; @@ -1639,7 +1641,12 @@ typedef struct StampData { } StampData; #undef STAMP_NAME_SIZE -static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix) +/** + * \param do_prefix: Include a label like "File ", "Date ", etc. in the stamp data strings. + * \param use_dynamic: Also include data that can change on a per-frame basis. + */ +static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, + bool use_dynamic) { char text[256]; struct tm *tl; @@ -1670,7 +1677,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d stamp_data->date[0] = '\0'; } - if (scene->r.stamp & R_STAMP_MARKER) { + if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) { const char *name = BKE_scene_find_last_marker_name(scene, CFRA); if (name) BLI_strncpy(text, name, sizeof(text)); @@ -1682,7 +1689,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d stamp_data->marker[0] = '\0'; } - if (scene->r.stamp & R_STAMP_TIME) { + if (use_dynamic && scene->r.stamp & R_STAMP_TIME) { const short timecode_style = USER_TIMECODE_SMPTE_FULL; BLI_timecode_string_from_time(text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style); BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), do_prefix ? "Timecode %s" : "%s", text); @@ -1691,7 +1698,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d stamp_data->time[0] = '\0'; } - if (scene->r.stamp & R_STAMP_FRAME) { + if (use_dynamic && scene->r.stamp & R_STAMP_FRAME) { char fmtstr[32]; int digits = 1; @@ -1705,14 +1712,23 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d stamp_data->frame[0] = '\0'; } - if (scene->r.stamp & R_STAMP_CAMERA) { + if (scene->r.stamp & R_STAMP_FRAME_RANGE) { + BLI_snprintf(stamp_data->frame_range, sizeof(stamp_data->frame), + do_prefix ? "Frame Range %d:%d" : "%d:%d", + scene->r.sfra, scene->r.efra); + } + else { + stamp_data->frame_range[0] = '\0'; + } + + if (use_dynamic && scene->r.stamp & R_STAMP_CAMERA) { BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>"); } else { stamp_data->camera[0] = '\0'; } - if (scene->r.stamp & R_STAMP_CAMERALENS) { + if (use_dynamic && scene->r.stamp & R_STAMP_CAMERALENS) { if (camera && camera->type == OB_CAMERA) { BLI_snprintf(text, sizeof(text), "%.2f", ((Camera *)camera->data)->lens); } @@ -1733,7 +1749,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d stamp_data->scene[0] = '\0'; } - if (scene->r.stamp & R_STAMP_SEQSTRIP) { + if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) { Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra); if (seq) BLI_strncpy(text, seq->name + 2, sizeof(text)); @@ -1749,7 +1765,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d Render *re = RE_GetSceneRender(scene); RenderStats *stats = re ? RE_GetStats(re) : NULL; - if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { + if (use_dynamic && stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { BLI_timecode_string_from_time_simple(text, sizeof(text), stats->lastframetime); BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), do_prefix ? "RenderTime %s" : "%s", text); @@ -1758,13 +1774,20 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d stamp_data->rendertime[0] = '\0'; } - if (stats && (scene->r.stamp & R_STAMP_MEMORY)) { + if (use_dynamic && stats && (scene->r.stamp & R_STAMP_MEMORY)) { BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak); } else { stamp_data->memory[0] = '\0'; } } + if (scene->r.stamp & R_STAMP_FRAME_RANGE) { + BLI_snprintf(stamp_data->frame_range, sizeof(stamp_data->frame_range), + do_prefix ? "Frame Range %d:%d" : "%d:%d", scene->r.sfra, scene->r.efra); + } + else { + stamp_data->frame_range[0] = '\0'; + } } /* Will always add prefix. */ @@ -1885,7 +1908,7 @@ void BKE_image_stamp_buf( display = IMB_colormanagement_display_get_named(display_device); if (stamp_data_template == NULL) { - stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0); + stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true); } else { stampdata_from_template(&stamp_data, scene, stamp_data_template); @@ -2106,13 +2129,28 @@ void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderRes } if (!allocate_only) - stampdata(scene, camera, stamp_data, 0); + stampdata(scene, camera, stamp_data, 0, true); if (!rr->stamp_data) { rr->stamp_data = stamp_data; } } +struct StampData *BKE_stamp_info_from_scene_static(Scene *scene) +{ + struct StampData *stamp_data; + + if (!(scene && (scene->r.stamp & R_STAMP_ALL))) + return NULL; + + /* Memory is allocated here (instead of by the caller) so that the caller + * doesn't have to know the size of the StampData struct. */ + stamp_data = MEM_callocN(sizeof(StampData), __func__); + stampdata(scene, NULL, stamp_data, 0, false); + + return stamp_data; +} + void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip) { if ((callback == NULL) || (stamp_data == NULL)) { @@ -2130,6 +2168,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall CALL(marker, "Marker"); CALL(time, "Time"); CALL(frame, "Frame"); + CALL(frame_range, "FrameRange"); CALL(camera, "Camera"); CALL(cameralens, "Lens"); CALL(scene, "Scene"); @@ -2173,27 +2212,31 @@ void BKE_stamp_data_free(struct StampData *stamp_data) } /* wrap for callback only */ -static void metadata_change_field(void *data, const char *propname, char *propvalue, int UNUSED(len)) +static void metadata_set_field(void *data, const char *propname, char *propvalue, int UNUSED(len)) { - IMB_metadata_change_field(data, propname, propvalue); + /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */ + struct ImBuf *imbuf = data; + IMB_metadata_set_field(imbuf->metadata, propname, propvalue); } static void metadata_get_field(void *data, const char *propname, char *propvalue, int len) { - IMB_metadata_get_field(data, propname, propvalue, len); + /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */ + struct ImBuf *imbuf = data; + IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len); } void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf) { struct StampData *stamp_data = rr->stamp_data; - - BKE_stamp_info_callback(ibuf, stamp_data, metadata_change_field, false); + IMB_metadata_ensure(&ibuf->metadata); + BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false); } void BKE_stamp_info_from_imbuf(RenderResult *rr, struct ImBuf *ibuf) { struct StampData *stamp_data = rr->stamp_data; - + IMB_metadata_ensure(&ibuf->metadata); BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true); } diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index ee80438db64..49f120de250 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -52,6 +52,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_colormanagement.h" +#include "IMB_metadata.h" #include "BLI_math_color_blend.h" diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 184016100c4..263c30cabca 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -86,6 +86,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_colormanagement.h" +#include "IMB_metadata.h" #include "BKE_context.h" #include "BKE_sound.h" @@ -946,6 +947,8 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r return; } + IMB_anim_load_metadata(sanim->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); @@ -5392,6 +5395,8 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad } } + IMB_anim_load_metadata(anim_arr[0]); + 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); diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index f745a840cea..85582ceea4c 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -53,6 +53,7 @@ #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_image.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_sound.h" @@ -62,6 +63,8 @@ #include "ffmpeg_compat.h" +struct StampData; + typedef struct FFMpegContext { int ffmpeg_type; int ffmpeg_codec; @@ -94,6 +97,8 @@ typedef struct FFMpegContext { bool audio_deinterleave; int audio_sample_size; + struct StampData *stamp_data; + #ifdef WITH_AUDASPACE AUD_Device *audio_mixdown_device; #endif @@ -836,6 +841,12 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va av_dict_set(dict, key, buffer, 0); } +static void ffmpeg_add_metadata_callback(void *data, const char *propname, char *propvalue, int len) +{ + AVDictionary **metadata = (AVDictionary **)data; + av_dict_set(metadata, propname, propvalue, 0); +} + static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports) { /* Handle to the output file */ @@ -994,6 +1005,11 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int goto fail; } } + + if (context->stamp_data != NULL) { + BKE_stamp_info_callback(&of->metadata, context->stamp_data, ffmpeg_add_metadata_callback, false); + } + if (avformat_write_header(of, NULL) < 0) { BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination"); goto fail; @@ -1168,6 +1184,7 @@ int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int r context->ffmpeg_autosplit_count = 0; context->ffmpeg_preview = preview; + context->stamp_data = BKE_stamp_info_from_scene_static(scene); success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports); #ifdef WITH_AUDASPACE @@ -1734,6 +1751,7 @@ void *BKE_ffmpeg_context_create(void) context->ffmpeg_autosplit = 0; context->ffmpeg_autosplit_count = 0; context->ffmpeg_preview = false; + context->stamp_data = NULL; return context; } @@ -1741,9 +1759,13 @@ void *BKE_ffmpeg_context_create(void) void BKE_ffmpeg_context_free(void *context_v) { FFMpegContext *context = context_v; - if (context) { - MEM_freeN(context); + if (context == NULL) { + return; + } + if (context->stamp_data) { + MEM_freeN(context->stamp_data); } + MEM_freeN(context); } #endif /* WITH_FFMPEG */ diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index d137806c575..48be9d1842f 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -103,6 +103,20 @@ int BLI_string_find_split_words( const char delim, int r_words[][2], int words_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +/** \name String Copy/Format Macros + * Avoid repeating destination with `sizeof(..)`. + * \note `ARRAY_SIZE` allows pointers on some platforms. + * \{ */ +#define STRNCPY(dst, src) \ + BLI_strncpy(dst, src, ARRAY_SIZE(dst)) +#define STRNCPY_RLEN(dst, src) \ + BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst)) +#define SNPRINTF(dst, format, ...) \ + BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__) +#define SNPRINTF_RLEN(dst, format, ...) \ + BLI_snprintf_rlen(dst, ARRAY_SIZE(dst), format, __VA_ARGS__) +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 3b899a3d302..390098b3ea3 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -66,6 +66,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "IMB_metadata.h" #include "UI_interface.h" #include "UI_interface_icons.h" @@ -2249,7 +2250,7 @@ static const char *meta_data_list[] = BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset) { - return (IMB_metadata_get_field(ibuf, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]); + return (IMB_metadata_get_field(ibuf->metadata, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]); } static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool is_top) diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index c3950d8eb83..e73f227dec8 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC IMB_colormanagement.h IMB_imbuf.h IMB_imbuf_types.h + IMB_metadata.h IMB_moviecache.h IMB_thumbs.h intern/IMB_allocimbuf.h @@ -81,7 +82,6 @@ set(SRC intern/IMB_filetype.h intern/IMB_filter.h intern/IMB_indexer.h - intern/IMB_metadata.h intern/imbuf.h # orphan include diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index a0fc273a746..e5cd21a3248 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -566,22 +566,6 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, const float col[4], struct ColorManagedDisplay *display, int x1, int y1, int x2, int y2); -/** - * - * \attention Defined in metadata.c - */ -/** read the field from the image info into the field - * \param img - the ImBuf that contains the image data - * \param key - the key of the field - * \param value - the data in the field, first one found with key is returned, - * memory has to be allocated by user. - * \param len - length of value buffer allocated by user. - * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise - */ -bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len); -bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field); -void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb); - /* exported for image tools in blender, to quickly allocate 32 bits rect */ void *imb_alloc_pixels(unsigned int x, unsigned int y, diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/IMB_metadata.h index bc0b2c70ecb..0a0d2c1faf6 100644 --- a/source/blender/imbuf/intern/IMB_metadata.h +++ b/source/blender/imbuf/IMB_metadata.h @@ -4,7 +4,7 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -33,7 +33,9 @@ #ifndef __IMB_METADATA_H__ #define __IMB_METADATA_H__ +struct anim; struct ImBuf; +struct IDProperty; /** The metadata is a list of key/value pairs (both char *) that can me * saved in the header of several image formats. @@ -41,26 +43,36 @@ struct ImBuf; * 'Software' and 'Description' (png standard) we'll use keys within the * Blender namespace, so should be called 'Blender::StampInfo' or 'Blender::FrameNum' * etc... + * + * The keys & values are stored in ID properties, in the group "metadata". */ +/** Ensure that the metadata property is a valid IDProperty object. + * This is a no-op when *metadata != NULL. + */ +void IMB_metadata_ensure(struct IDProperty **metadata); +void IMB_metadata_free(struct IDProperty *metadata); -/* free blender ImMetaData struct */ -void IMB_metadata_free(struct ImBuf *img); +/** Read the field from the image info into the field. + * \param metadata - the IDProperty that contains the metadata + * \param key - the key of the field + * \param value - the data in the field, first one found with key is returned, + * memory has to be allocated by user. + * \param len - length of value buffer allocated by user. + * \return - 1 (true) if metadata is present and value for the key found, 0 (false) otherwise + */ +bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *value, const size_t len); -/** set user data in the ImMetaData struct, which has to be allocated with IMB_metadata_create - * before calling this function. - * \param img - the ImBuf that contains the image data +/** Set user data in the metadata. + * If the field already exists its value is overwritten, otherwise the field + * will be added with the given value. + * \param metadata - the IDProperty that contains the metadata * \param key - the key of the field * \param value - the data to be written to the field. zero terminated string - * \return - 1 (true) if ImageInfo present, 0 (false) otherwise */ -bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value); +void IMB_metadata_set_field(struct IDProperty *metadata, const char *key, const char *value); -/** delete the key/field par in the ImMetaData struct. - * \param img - the ImBuf that contains the image data - * \param key - the key of the field - * \return - 1 (true) if delete the key/field, 0 (false) otherwise - */ -bool IMB_metadata_del_field(struct ImBuf *img, const char *key); +void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb); +struct IDProperty *IMB_anim_load_metadata(struct anim *anim); #endif /* __IMB_METADATA_H__ */ diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index c4c4f4405a5..6fa31e122cc 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -93,6 +93,7 @@ struct _AviMovie; struct anim_index; +struct IDProperty; struct anim { int ib_flags; @@ -158,6 +159,8 @@ struct anim { char colorspace[64]; char suffix[64]; /* MAX_NAME - multiview */ + + struct IDProperty *metadata; }; #endif diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 7fc4a65d8d7..faa0b5f7b6e 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -219,7 +219,7 @@ void IMB_freeImBuf(ImBuf *ibuf) IMB_freezbufImBuf(ibuf); IMB_freezbuffloatImBuf(ibuf); freeencodedbufferImBuf(ibuf); - IMB_metadata_free(ibuf); + IMB_metadata_free(ibuf->metadata); colormanage_cache_free(ibuf); if (ibuf->dds_data.data != NULL) { diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index cc8a38d5bf4..f842b69418e 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -80,6 +80,7 @@ #include "IMB_anim.h" #include "IMB_indexer.h" +#include "IMB_metadata.h" #ifdef WITH_FFMPEG # include "BKE_global.h" /* ENDIAN_ORDER */ @@ -220,6 +221,7 @@ void IMB_free_anim(struct anim *anim) free_anim_ffmpeg(anim); #endif IMB_free_indices(anim); + IMB_metadata_free(anim->metadata); MEM_freeN(anim); } @@ -239,6 +241,26 @@ void IMB_close_anim_proxies(struct anim *anim) IMB_free_indices(anim); } +struct IDProperty *IMB_anim_load_metadata(struct anim *anim) +{ +#ifdef WITH_FFMPEG + AVDictionaryEntry *entry = NULL; + + BLI_assert(anim->pFormatCtx != NULL); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "METADATA FETCH\n"); + + while (true) { + entry = av_dict_get(anim->pFormatCtx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX); + if (entry == NULL) break; + + /* Delay creation of the property group until there is actual metadata to put in there. */ + IMB_metadata_ensure(&anim->metadata); + IMB_metadata_set_field(anim->metadata, entry->key, entry->value); + } +#endif + return anim->metadata; +} + struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE]) { struct anim *anim; diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index e28c8122006..b2197ecb3b5 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -49,6 +49,7 @@ #include "IMB_filetype.h" #include "IMB_filter.h" #include "IMB_moviecache.h" +#include "IMB_metadata.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 35c7b6363a1..ef9217fbc8c 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -382,7 +382,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla * the information when we write * it back to disk. */ - IMB_metadata_add_field(ibuf, "None", str); + IMB_metadata_ensure(&ibuf->metadata); + IMB_metadata_set_field(ibuf->metadata, "None", str); ibuf->flags |= IB_metadata; MEM_freeN(str); goto next_stamp_marker; @@ -408,7 +409,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla *value = '\0'; /* need finish the key string */ value++; - IMB_metadata_add_field(ibuf, key, value); + IMB_metadata_ensure(&ibuf->metadata); + IMB_metadata_set_field(ibuf->metadata, key, value); ibuf->flags |= IB_metadata; MEM_freeN(str); next_stamp_marker: diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c index da39967a4fe..ef103f7afcf 100644 --- a/source/blender/imbuf/intern/metadata.c +++ b/source/blender/imbuf/intern/metadata.c @@ -45,97 +45,69 @@ #include "IMB_metadata.h" +#define METADATA_MAX_VALUE_LENGTH 1024 -void IMB_metadata_free(struct ImBuf *img) +void IMB_metadata_ensure(struct IDProperty **metadata) { - if (!img) + if (*metadata != NULL) { return; - if (!img->metadata) { + } + + IDPropertyTemplate val; + *metadata = IDP_New(IDP_GROUP, &val, "metadata"); +} + +void IMB_metadata_free(struct IDProperty *metadata) +{ + if (metadata == NULL) { return; } - IDP_FreeProperty(img->metadata); - MEM_freeN(img->metadata); + IDP_FreeProperty(metadata); + MEM_freeN(metadata); } -bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, const size_t len) +bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *field, const size_t len) { IDProperty *prop; - bool retval = false; - - if (!img) - return false; - if (!img->metadata) + if (metadata == NULL) { return false; + } - prop = IDP_GetPropertyFromGroup(img->metadata, key); + prop = IDP_GetPropertyFromGroup(metadata, key); if (prop && prop->type == IDP_STRING) { BLI_strncpy(field, IDP_String(prop), len); - retval = true; + return true; } - return retval; + return false; } void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb) { BLI_assert(dimb != simb); if (simb->metadata) { - IMB_metadata_free(dimb); + IMB_metadata_free(dimb->metadata); dimb->metadata = IDP_CopyProperty(simb->metadata); } } -bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value) +void IMB_metadata_set_field(struct IDProperty *metadata, const char *key, const char *value) { - IDProperty *prop; - - if (!img) - return false; + BLI_assert(metadata); + IDProperty *prop = IDP_GetPropertyFromGroup(metadata, key); - if (!img->metadata) { - IDPropertyTemplate val; - img->metadata = IDP_New(IDP_GROUP, &val, "metadata"); + if (prop != NULL && prop->type != IDP_STRING) { + IDP_FreeFromGroup(metadata, prop); + prop = NULL; } - prop = IDP_NewString(value, key, 512); - return IDP_AddToGroup(img->metadata, prop); -} - -bool IMB_metadata_del_field(struct ImBuf *img, const char *key) -{ - IDProperty *prop; - - if ((!img) || (!img->metadata)) - return false; - - prop = IDP_GetPropertyFromGroup(img->metadata, key); - - if (prop) { - IDP_FreeFromGroup(img->metadata, prop); + if (prop == NULL) { + prop = IDP_NewString(value, key, METADATA_MAX_VALUE_LENGTH); + IDP_AddToGroup(metadata, prop); } - return false; -} - -bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field) -{ - IDProperty *prop; - if (!img) - return false; - - prop = (img->metadata) ? IDP_GetPropertyFromGroup(img->metadata, key) : NULL; - - if (!prop) { - return (IMB_metadata_add_field(img, key, field)); - } - else if (prop->type == IDP_STRING) { - IDP_AssignString(prop, field, 1024); - return true; - } - else { - return false; - } + IDP_AssignString(prop, value, METADATA_MAX_VALUE_LENGTH); } diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 4e85d70d382..ad04f1fb78d 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1790,12 +1790,13 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, const Header & header = file->header(0); Header::ConstIterator iter; + IMB_metadata_ensure(&ibuf->metadata); for (iter = header.begin(); iter != header.end(); iter++) { const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name()); /* not all attributes are string attributes so we might get some NULLs here */ if (attrib) { - IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str()); + IMB_metadata_set_field(ibuf->metadata, iter.name(), attrib->value().c_str()); ibuf->flags |= IB_metadata; } } diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 857f72e10eb..29fbe79d8db 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -759,8 +759,9 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors if (flags & IB_metadata) { png_text *text_chunks; int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); + IMB_metadata_ensure(&ibuf->metadata); for (int i = 0; i < count; i++) { - IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); + IMB_metadata_set_field(ibuf->metadata, text_chunks[i].key, text_chunks[i].text); ibuf->flags |= IB_metadata; } } diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index ba72decf44d..86e1fba9af7 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -430,16 +430,17 @@ static ImBuf *thumb_create_ex( IMB_scaleImBuf(img, ex, ey); } BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri); - IMB_metadata_change_field(img, "Description", desc); - IMB_metadata_change_field(img, "Software", "Blender"); - IMB_metadata_change_field(img, "Thumb::URI", uri); - IMB_metadata_change_field(img, "Thumb::MTime", mtime); + IMB_metadata_ensure(&img->metadata); + IMB_metadata_set_field(img->metadata, "Software", "Blender"); + IMB_metadata_set_field(img->metadata, "Thumb::URI", uri); + IMB_metadata_set_field(img->metadata, "Description", desc); + IMB_metadata_set_field(img->metadata, "Thumb::MTime", mtime); if (use_hash) { - IMB_metadata_change_field(img, "X-Blender::Hash", hash); + IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash); } if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) { - IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth); - IMB_metadata_change_field(img, "Thumb::Image::Height", cheight); + IMB_metadata_set_field(img->metadata, "Thumb::Image::Width", cwidth); + IMB_metadata_set_field(img->metadata, "Thumb::Image::Height", cheight); } img->ftype = IMB_FTYPE_PNG; img->planes = 32; @@ -589,7 +590,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash); - if (IMB_metadata_get_field(img, "Thumb::MTime", mtime, sizeof(mtime))) { + if (IMB_metadata_get_field(img->metadata, "Thumb::MTime", mtime, sizeof(mtime))) { regenerate = (st.st_mtime != atol(mtime)); } else { @@ -598,7 +599,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source } if (use_hash && !regenerate) { - if (IMB_metadata_get_field(img, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) { + if (IMB_metadata_get_field(img->metadata, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) { regenerate = !STREQ(thumb_hash, thumb_hash_curr); } else { diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index d2810efca08..a18c9cf3712 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1834,10 +1834,11 @@ enum { #define R_STAMP_STRIPMETA 0x1000 #define R_STAMP_MEMORY 0x2000 #define R_STAMP_HIDE_LABELS 0x4000 +#define R_STAMP_FRAME_RANGE 0x8000 #define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \ R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \ R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \ - R_STAMP_HIDE_LABELS) + R_STAMP_HIDE_LABELS|R_STAMP_FRAME_RANGE) /* RenderData.alphamode */ #define R_ADDSKY 0 diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index c35ca5c42e4..088b2b67af5 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -793,6 +793,14 @@ static int rna_ID_is_updated_data_get(PointerRNA *ptr) return ((data->recalc & ID_RECALC_ALL) != 0); } +static IDProperty *rna_IDPropertyWrapPtr_idprops(PointerRNA *ptr, bool UNUSED(create)) +{ + if (ptr == NULL) { + return NULL; + } + return ptr->data; +} + #else static void rna_def_ID_properties(BlenderRNA *brna) @@ -1180,6 +1188,20 @@ static void rna_def_library(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Reload this library and all its linked data-blocks"); } + +/** + * \attention This is separate from the above. It allows for RNA functions to + * return an IDProperty *. See MovieClip.metadata for a usage example. + **/ +static void rna_def_idproperty_wrap_ptr(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "IDPropertyWrapPtr", NULL); + RNA_def_struct_idprops_func(srna, "rna_IDPropertyWrapPtr_idprops"); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); +} + void RNA_def_ID(BlenderRNA *brna) { StructRNA *srna; @@ -1198,6 +1220,7 @@ void RNA_def_ID(BlenderRNA *brna) rna_def_ID_properties(brna); rna_def_ID_materials(brna); rna_def_library(brna); + rna_def_idproperty_wrap_ptr(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index 850b1cd706b..c663119eb42 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -33,6 +33,7 @@ #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" +#include "RNA_access.h" #include "RNA_define.h" #include "rna_internal.h" @@ -44,6 +45,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "IMB_metadata.h" #ifdef RNA_RUNTIME @@ -103,6 +105,22 @@ static void rna_MovieClipUser_proxy_render_settings_update(Main *UNUSED(bmain), } } +static PointerRNA rna_MovieClip_metadata_get(MovieClip *clip) +{ + if (clip == NULL || clip->anim == NULL) { + return PointerRNA_NULL; + } + + IDProperty *metadata = IMB_anim_load_metadata(clip->anim); + if (metadata == NULL) { + return PointerRNA_NULL; + } + + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_IDPropertyWrapPtr, metadata, &ptr); + return ptr; +} + #else static void rna_def_movieclip_proxy(BlenderRNA *brna) @@ -257,6 +275,8 @@ static void rna_def_movieclip(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; static const EnumPropertyItem clip_source_items[] = { {MCLIP_SRC_SEQUENCE, "SEQUENCE", 0, "Image Sequence", "Multiple image files, as a sequence"}, @@ -348,6 +368,14 @@ static void rna_def_movieclip(BlenderRNA *brna) RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); + /* metadata */ + func = RNA_def_function(srna, "metadata", "rna_MovieClip_metadata_get"); + RNA_def_function_ui_description(func, "Retrieve metadata of the movie file"); + /* return type */ + parm = RNA_def_pointer(func, "metadata", "IDPropertyWrapPtr", "", "Dict-like object containing the metadata"); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + rna_def_animdata_common(srna); } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 5d91cd50935..ac9fce46384 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -6137,7 +6137,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stamp_date", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_DATE); - RNA_def_property_ui_text(prop, "Stamp Date", "Include the current date in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Date", "Include the current date in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_frame", PROP_BOOLEAN, PROP_NONE); @@ -6145,6 +6145,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stamp Frame", "Include the frame number in image metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "use_stamp_frame_range", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_FRAME_RANGE); + RNA_def_property_ui_text(prop, "Stamp Frame", "Include the rendered frame range in image/video metadata"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "use_stamp_camera", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_CAMERA); RNA_def_property_ui_text(prop, "Stamp Camera", "Include the name of the active camera in image metadata"); @@ -6157,12 +6162,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stamp_scene", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_SCENE); - RNA_def_property_ui_text(prop, "Stamp Scene", "Include the name of the active scene in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Scene", "Include the name of the active scene in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_note", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_NOTE); - RNA_def_property_ui_text(prop, "Stamp Note", "Include a custom note in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Note", "Include a custom note in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_marker", PROP_BOOLEAN, PROP_NONE); @@ -6172,7 +6177,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stamp_filename", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_FILENAME); - RNA_def_property_ui_text(prop, "Stamp Filename", "Include the .blend filename in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Filename", "Include the .blend filename in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_sequencer_strip", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 81c05433e66..33621af69af 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -41,6 +41,8 @@ #include "BKE_sequencer.h" #include "BKE_sound.h" +#include "IMB_metadata.h" + #include "MEM_guardedalloc.h" #include "RNA_access.h" @@ -587,6 +589,27 @@ static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create) return seq->prop; } +static PointerRNA rna_MovieSequence_metadata_get(Sequence *seq) +{ + if (seq == NULL || seq->anims.first == NULL) { + return PointerRNA_NULL; + } + + StripAnim *sanim = seq->anims.first; + if (sanim->anim == NULL) { + return PointerRNA_NULL; + } + + IDProperty *metadata = IMB_anim_load_metadata(sanim->anim); + if (metadata == NULL) { + return PointerRNA_NULL; + } + + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_IDPropertyWrapPtr, metadata, &ptr); + return ptr; +} + static PointerRNA rna_SequenceEditor_meta_stack_get(CollectionPropertyIterator *iter) { ListBaseIterator *internal = &iter->internal.listbase; @@ -1963,7 +1986,9 @@ static void rna_def_movie(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "MovieSequence", "Sequence"); RNA_def_struct_ui_text(srna, "Movie Sequence", "Sequence strip to load a video"); RNA_def_struct_sdna(srna, "Sequence"); @@ -1995,6 +2020,14 @@ static void rna_def_movie(BlenderRNA *brna) "rna_Sequence_filepath_set"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update"); + /* metadata */ + func = RNA_def_function(srna, "metadata", "rna_MovieSequence_metadata_get"); + RNA_def_function_ui_description(func, "Retrieve metadata of the movie file"); + /* return type */ + parm = RNA_def_pointer(func, "metadata", "IDPropertyWrapPtr", "", "Dict-like object containing the metadata"); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + /* multiview */ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_VIEWS); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 84b64b84298..d6e45788942 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -88,6 +88,7 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "IMB_metadata.h" #include "RE_engine.h" #include "RE_pipeline.h" |