Further improvement for multi-threaded proxies
Handle sequences in a special case for dealing with sequence sources. Namely handle separate frames in separate threads, but do disk read from a critical section since HDD is not so friendly with lots threads requesting for data from it. Makes proxy building much faster than it was before.
This commit is contained in:
@@ -64,9 +64,14 @@ void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUs
|
||||
void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
|
||||
int cfra, int *build_sizes, int build_count, int undistorted);
|
||||
|
||||
void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip, struct ImBuf *ibuf, struct MovieDistortion *distortion,
|
||||
int cfra, int *build_sizes, int build_count, int undistorted);
|
||||
|
||||
float BKE_movieclip_remap_scene_to_clip_frame(struct MovieClip *clip, float framenr);
|
||||
float BKE_movieclip_remap_clip_to_scene_frame(struct MovieClip *clip, float framenr);
|
||||
|
||||
void BKE_movieclip_filename_for_frame(struct MovieClip *clip, int framenr, char *name);
|
||||
|
||||
/* cacheing flags */
|
||||
#define MOVIECLIP_CACHE_SKIP (1 << 0)
|
||||
|
||||
|
||||
@@ -1230,7 +1230,7 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip
|
||||
scopes->ok = TRUE;
|
||||
}
|
||||
|
||||
static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, int undistorted)
|
||||
static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, int undistorted, bool threaded)
|
||||
{
|
||||
char name[FILE_MAX];
|
||||
int quality, rectx, recty;
|
||||
@@ -1244,7 +1244,10 @@ static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, i
|
||||
|
||||
scaleibuf = IMB_dupImBuf(ibuf);
|
||||
|
||||
IMB_scaleImBuf_threaded(scaleibuf, (short)rectx, (short)recty);
|
||||
if (threaded)
|
||||
IMB_scaleImBuf_threaded(scaleibuf, (short)rectx, (short)recty);
|
||||
else
|
||||
IMB_scaleImBuf(scaleibuf, (short)rectx, (short)recty);
|
||||
|
||||
quality = clip->proxy.quality;
|
||||
scaleibuf->ftype = JPG | quality;
|
||||
@@ -1253,6 +1256,10 @@ static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, i
|
||||
if (scaleibuf->planes == 32)
|
||||
scaleibuf->planes = 24;
|
||||
|
||||
/* TODO: currently the most weak part of multithreaded proxies,
|
||||
* could be solved in a way that thread only prepares memory
|
||||
* buffer and write to disk happens separately
|
||||
*/
|
||||
BLI_lock_thread(LOCK_MOVIECLIP);
|
||||
|
||||
BLI_make_existing_file(name);
|
||||
@@ -1264,6 +1271,9 @@ static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, i
|
||||
IMB_freeImBuf(scaleibuf);
|
||||
}
|
||||
|
||||
/* note: currently used by proxy job for movies, threading happens within single frame
|
||||
* (meaning scaling shall be threaded)
|
||||
*/
|
||||
void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
|
||||
int cfra, int *build_sizes, int build_count, int undistorted)
|
||||
{
|
||||
@@ -1287,7 +1297,7 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct Movi
|
||||
tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
|
||||
|
||||
for (i = 0; i < build_count; i++)
|
||||
movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted);
|
||||
movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, true);
|
||||
|
||||
IMB_freeImBuf(ibuf);
|
||||
|
||||
@@ -1296,6 +1306,30 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct Movi
|
||||
}
|
||||
}
|
||||
|
||||
/* note: currently used by proxy job for sequences, threading happens within sequence
|
||||
* (different threads handles different frames, no threading within frame is needed)
|
||||
*/
|
||||
void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, struct MovieDistortion *distortion,
|
||||
int cfra, int *build_sizes, int build_count, int undistorted)
|
||||
{
|
||||
if (!build_count)
|
||||
return;
|
||||
|
||||
if (ibuf) {
|
||||
ImBuf *tmpibuf = ibuf;
|
||||
int i;
|
||||
|
||||
if (undistorted)
|
||||
tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
|
||||
|
||||
for (i = 0; i < build_count; i++)
|
||||
movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, false);
|
||||
|
||||
if (tmpibuf != ibuf)
|
||||
IMB_freeImBuf(tmpibuf);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_movieclip_free(MovieClip *clip)
|
||||
{
|
||||
BKE_sequencer_clear_movieclip_in_clipboard(clip);
|
||||
@@ -1384,3 +1418,14 @@ float BKE_movieclip_remap_clip_to_scene_frame(MovieClip *clip, float framenr)
|
||||
{
|
||||
return framenr + (float) clip->start_frame - 1.0f;
|
||||
}
|
||||
|
||||
void BKE_movieclip_filename_for_frame(MovieClip *clip, int framenr, char *name)
|
||||
{
|
||||
if (clip->source != MCLIP_SRC_MOVIE) {
|
||||
get_sequence_fname(clip, framenr, name);
|
||||
}
|
||||
else {
|
||||
BLI_strncpy(name, clip->name, FILE_MAX);
|
||||
BLI_path_abs(name, ID_BLEND_PATH(G.main, &clip->id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,14 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
@@ -37,6 +45,7 @@
|
||||
#include "DNA_scene_types.h" /* min/max frames */
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rect.h"
|
||||
@@ -972,49 +981,39 @@ static int proxy_bitflag_to_array(int size_flag, int build_sizes[4], int undisto
|
||||
return build_count;
|
||||
}
|
||||
|
||||
/* only this runs inside thread */
|
||||
static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
|
||||
/* simple case for movies -- handle frame-by-frame, do threading within single frame */
|
||||
static void do_movie_proxy(void *pjv, int *UNUSED(build_sizes), int UNUSED(build_count),
|
||||
int *build_undistort_sizes, int build_undistort_count,
|
||||
short *stop, short *do_update, float *progress)
|
||||
{
|
||||
ProxyJob *pj = pjv;
|
||||
Scene *scene = pj->scene;
|
||||
MovieClip *clip = pj->clip;
|
||||
struct MovieDistortion *distortion = NULL;
|
||||
short size_flag;
|
||||
int cfra, sfra = SFRA, efra = EFRA;
|
||||
int build_sizes[4], build_count = 0;
|
||||
int build_undistort_sizes[4], build_undistort_count = 0;
|
||||
|
||||
size_flag = clip->proxy.build_size_flag;
|
||||
if (pj->index_context)
|
||||
IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
|
||||
|
||||
build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0);
|
||||
build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1);
|
||||
if (!build_undistort_count) {
|
||||
if (*stop)
|
||||
pj->stop = 1;
|
||||
|
||||
if (clip->source == MCLIP_SRC_MOVIE) {
|
||||
if (pj->index_context)
|
||||
IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
|
||||
|
||||
if (!build_undistort_count) {
|
||||
if (*stop)
|
||||
pj->stop = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
sfra = 1;
|
||||
efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
sfra = 1;
|
||||
efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
|
||||
}
|
||||
|
||||
if (build_undistort_count) {
|
||||
int threads = BLI_system_thread_count();
|
||||
|
||||
distortion = BKE_tracking_distortion_new();
|
||||
BKE_tracking_distortion_set_threads(distortion, threads);
|
||||
}
|
||||
|
||||
for (cfra = sfra; cfra <= efra; cfra++) {
|
||||
if (clip->source != MCLIP_SRC_MOVIE)
|
||||
BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, NULL, cfra, build_sizes, build_count, 0);
|
||||
|
||||
BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, distortion, cfra,
|
||||
build_undistort_sizes, build_undistort_count, 1);
|
||||
|
||||
@@ -1032,6 +1031,193 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
|
||||
pj->stop = 1;
|
||||
}
|
||||
|
||||
/* *****
|
||||
* special case for sequences -- handle different frames in different threads,
|
||||
* loading from disk happens in critical section, decoding frame happens from
|
||||
* thread for maximal speed
|
||||
*/
|
||||
|
||||
typedef struct ProxyQueue {
|
||||
int cfra;
|
||||
int sfra;
|
||||
int efra;
|
||||
SpinLock spin;
|
||||
|
||||
short *stop;
|
||||
short *do_update;
|
||||
float *progress;
|
||||
} ProxyQueue;
|
||||
|
||||
typedef struct ProxyThread {
|
||||
MovieClip *clip;
|
||||
ProxyQueue *queue;
|
||||
|
||||
struct MovieDistortion *distortion;
|
||||
|
||||
int *build_sizes, build_count;
|
||||
int *build_undistort_sizes, build_undistort_count;
|
||||
} ProxyThread;
|
||||
|
||||
static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip, size_t *size_r, int *cfra_r)
|
||||
{
|
||||
unsigned char *mem = NULL;
|
||||
|
||||
BLI_spin_lock(&queue->spin);
|
||||
if (!*queue->stop && queue->cfra <= queue->efra) {
|
||||
char name[FILE_MAX];
|
||||
size_t size;
|
||||
int file;
|
||||
|
||||
BKE_movieclip_filename_for_frame(clip, queue->cfra, name);
|
||||
|
||||
file = open(name, O_BINARY | O_RDONLY, 0);
|
||||
if (file < 0) {
|
||||
BLI_spin_unlock(&queue->spin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = BLI_file_descriptor_size(file);
|
||||
if (size < 1) {
|
||||
close(file);
|
||||
BLI_spin_unlock(&queue->spin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mem = MEM_mallocN(size, "movieclip proxy memory file");
|
||||
|
||||
if (read(file, mem, size) != size) {
|
||||
close(file);
|
||||
BLI_spin_unlock(&queue->spin);
|
||||
MEM_freeN(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size_r = size;
|
||||
*cfra_r = queue->cfra;
|
||||
|
||||
queue->cfra++;
|
||||
close(file);
|
||||
|
||||
*queue->do_update = 1;
|
||||
*queue->progress = (float)(queue->cfra - queue->sfra) / (queue->efra - queue->sfra);
|
||||
}
|
||||
BLI_spin_unlock(&queue->spin);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void *do_proxy_thread(void *data_v)
|
||||
{
|
||||
ProxyThread *data = (ProxyThread *) data_v;
|
||||
unsigned char *mem;
|
||||
size_t size;
|
||||
int cfra;
|
||||
|
||||
while ((mem = proxy_thread_next_frame(data->queue, data->clip, &size, &cfra))) {
|
||||
ImBuf *ibuf;
|
||||
|
||||
ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect, NULL, "proxy frame");
|
||||
|
||||
BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, NULL, cfra,
|
||||
data->build_sizes, data->build_count, FALSE);
|
||||
|
||||
BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, data->distortion, cfra,
|
||||
data->build_undistort_sizes, data->build_undistort_count, TRUE);
|
||||
|
||||
IMB_freeImBuf(ibuf);
|
||||
|
||||
MEM_freeN(mem);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
|
||||
int *build_undistort_sizes, int build_undistort_count,
|
||||
short *stop, short *do_update, float *progress)
|
||||
{
|
||||
ProxyJob *pj = pjv;
|
||||
MovieClip *clip = pj->clip;
|
||||
Scene *scene = pj->scene;
|
||||
int sfra = SFRA, efra = EFRA;
|
||||
ProxyThread *handles;
|
||||
ListBase threads;
|
||||
int i, tot_thread = BLI_system_thread_count();
|
||||
ProxyQueue queue;
|
||||
|
||||
BLI_spin_init(&queue.spin);
|
||||
|
||||
queue.cfra = sfra;
|
||||
queue.sfra = sfra;
|
||||
queue.efra = efra;
|
||||
queue.stop = stop;
|
||||
queue.do_update = do_update;
|
||||
queue.progress = progress;
|
||||
|
||||
handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
|
||||
|
||||
if (tot_thread > 1)
|
||||
BLI_init_threads(&threads, do_proxy_thread, tot_thread);
|
||||
|
||||
for (i = 0; i < tot_thread; i++) {
|
||||
ProxyThread *handle = &handles[i];
|
||||
|
||||
handle->clip = clip;
|
||||
handle->queue = &queue;
|
||||
|
||||
handle->build_count = build_count;
|
||||
handle->build_sizes = build_sizes;
|
||||
|
||||
handle->build_undistort_count = build_undistort_count;
|
||||
handle->build_undistort_sizes = build_undistort_sizes;
|
||||
|
||||
if (build_undistort_count)
|
||||
handle->distortion = BKE_tracking_distortion_new();
|
||||
|
||||
if (tot_thread > 1)
|
||||
BLI_insert_thread(&threads, handle);
|
||||
}
|
||||
|
||||
if (tot_thread > 1)
|
||||
BLI_end_threads(&threads);
|
||||
else
|
||||
do_proxy_thread(handles);
|
||||
|
||||
MEM_freeN(handles);
|
||||
|
||||
if (build_undistort_count) {
|
||||
for (i = 0; i < tot_thread; i++) {
|
||||
ProxyThread *handle = &handles[i];
|
||||
|
||||
BKE_tracking_distortion_free(handle->distortion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
|
||||
{
|
||||
ProxyJob *pj = pjv;
|
||||
MovieClip *clip = pj->clip;
|
||||
|
||||
short size_flag;
|
||||
int build_sizes[4], build_count = 0;
|
||||
int build_undistort_sizes[4], build_undistort_count = 0;
|
||||
|
||||
size_flag = clip->proxy.build_size_flag;
|
||||
|
||||
build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0);
|
||||
build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1);
|
||||
|
||||
if (clip->source == MCLIP_SRC_MOVIE) {
|
||||
do_movie_proxy(pjv, build_sizes, build_count, build_undistort_sizes,
|
||||
build_undistort_count, stop, do_update, progress);
|
||||
}
|
||||
else {
|
||||
do_sequence_proxy(pjv, build_sizes, build_count, build_undistort_sizes,
|
||||
build_undistort_count, stop, do_update, progress);
|
||||
}
|
||||
}
|
||||
|
||||
static void proxy_endjob(void *pjv)
|
||||
{
|
||||
ProxyJob *pj = pjv;
|
||||
|
||||
Reference in New Issue
Block a user