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:
authorSybren A. Stüvel <sybren@stuvel.eu>2018-04-05 17:31:59 +0300
committerSybren A. Stüvel <sybren@stuvel.eu>2018-04-05 17:50:23 +0300
commit6374d390d366e582465dc7cfb62e0443b060cc6e (patch)
tree142129355044e04da97cc77963168f9b4d81cdbf
parentb0a767b85b0acacc40a414dd3f961b206a6b22f0 (diff)
Write StampData metadata to video files
This is currently only supported by FFmpeg (so not frameserver, AVI RAW, or AVI JPEG), and only seems to work when using Matroska or Ogg Theora containers. Only metadata that doesn't change from frame to frame is written to video files. This distinction is visible in the UI by looking at the stamp checkbox tooltips (they either mention "image" or "image/video"). Part of: https://developer.blender.org/D2273 Reviewed by: @campbellbarton
-rw-r--r--source/blender/blenkernel/BKE_image.h5
-rw-r--r--source/blender/blenkernel/intern/image.c43
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c26
-rw-r--r--source/blender/makesrna/intern/rna_scene.c8
4 files changed, 65 insertions, 17 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 e65692fb1b4..34891d95669 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -1623,6 +1623,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 +1640,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 +1676,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 +1688,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 +1697,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 +1711,14 @@ 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 (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 +1739,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 +1755,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,7 +1764,7 @@ 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 {
@@ -1885,7 +1891,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 +2112,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)) {
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 5415fbb8ae1..aa81b39d196 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/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index e6ba459a406..94206710028 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -6355,7 +6355,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);
@@ -6375,12 +6375,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);
@@ -6390,7 +6390,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);