示例#1
0
struct ImBuf * IMB_anim_previewframe(struct anim * anim) {
	struct ImBuf * ibuf = NULL;
	int position = 0;
	
	ibuf = IMB_anim_absolute(anim, 0);
	if (ibuf) {
		IMB_freeImBuf(ibuf);
		position = anim->duration / 2;
		ibuf = IMB_anim_absolute(anim, position);
	}
	return ibuf;
}
示例#2
0
static ImBuf *movieclip_load_movie_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
{
    ImBuf *ibuf = NULL;
    int tc = get_timecode(clip, flag);
    int proxy = rendersize_to_proxy(user, flag);

    movieclip_open_anim_file(clip);

    if (clip->anim) {
        int dur;
        int fra;

        dur = IMB_anim_get_duration(clip->anim, tc);
        fra = framenr - 1;

        if (fra < 0)
            fra = 0;

        if (fra > (dur - 1))
            fra = dur - 1;

        ibuf = IMB_anim_absolute(clip->anim, fra, tc, proxy);
    }

    return ibuf;
}
示例#3
0
static void index_rebuild_fallback(FallbackIndexBuilderContext *context,
                                   short *stop, short *do_update, float *progress)
{
	int cnt = IMB_anim_get_duration(context->anim, IMB_TC_NONE);
	int i, pos;
	struct anim *anim = context->anim;

	for (pos = 0; pos < cnt; pos++) {
		struct ImBuf *ibuf = IMB_anim_absolute(anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
		struct ImBuf *tmp_ibuf = IMB_dupImBuf(ibuf);
		float next_progress = (float) pos / (float) cnt;

		if (*progress != next_progress) {
			*progress = next_progress;
			*do_update = TRUE;
		}
		
		if (*stop) {
			break;
		}

		IMB_flipy(tmp_ibuf);

		for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
			if (context->proxy_sizes_in_use & proxy_sizes[i]) {
				int x = anim->x * proxy_fac[i];
				int y = anim->y * proxy_fac[i];

				struct ImBuf *s_ibuf = IMB_dupImBuf(tmp_ibuf);

				IMB_scalefastImBuf(s_ibuf, x, y);

				IMB_convert_rgba_to_abgr(s_ibuf);
	
				AVI_write_frame(context->proxy_ctx[i], pos,
				                AVI_FORMAT_RGB32,
				                s_ibuf->rect, x * y * 4);

				/* note that libavi free's the buffer... */
				s_ibuf->rect = NULL;

				IMB_freeImBuf(s_ibuf);
			}
		}

		IMB_freeImBuf(tmp_ibuf);
		IMB_freeImBuf(ibuf);
	}
}
示例#4
0
static ImBuf *movieclip_load_movie_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
{
	ImBuf *ibuf = NULL;
	int tc = get_timecode(clip, flag);
	int proxy = rendersize_to_proxy(user, flag);

	movieclip_open_anim_file(clip);

	if (clip->anim) {
		int fra = framenr - clip->start_frame + clip->frame_offset;

		ibuf = IMB_anim_absolute(clip->anim, fra, tc, proxy);
	}

	return ibuf;
}
示例#5
0
/* return path for restart */
static char *wm_main_playanim_intern(int argc, const char **argv)
{
	struct ImBuf *ibuf = NULL;
	static char filepath[FILE_MAX];	/* abused to return dropped file path */
	GHOST_TUns32 maxwinx, maxwiny;
	int i;
	/* This was done to disambiguate the name for use under c++. */
	struct anim *anim = NULL;
	int start_x = 0, start_y = 0;
	int sfra = -1;
	int efra = -1;
	int totblock;
	
	PlayState ps = {0};

	/* ps.doubleb   = TRUE;*/ /* UNUSED */
	ps.go        = TRUE;
	ps.direction = TRUE;
	ps.next_frame = 1;
	ps.once      = FALSE;
	ps.turbo     = FALSE;
	ps.pingpong  = FALSE;
	ps.noskip    = FALSE;
	ps.sstep     = FALSE;
	ps.wait2     = FALSE;
	ps.stopped   = FALSE;
	ps.picture   = NULL;
	ps.dropped_file[0] = 0;
	ps.zoom      = 1.0f;
	/* resetmap = FALSE */

	ps.fstep     = 1;

	ps.fontid = -1;

	while (argc > 1) {
		if (argv[1][0] == '-') {
			switch (argv[1][1]) {
				case 'm':
					fromdisk = TRUE;
					break;
				case 'p':
					if (argc > 3) {
						start_x = atoi(argv[2]);
						start_y = atoi(argv[3]);
						argc -= 2;
						argv += 2;
					}
					else {
						printf("too few arguments for -p (need 2): skipping\n");
					}
					break;
				case 'f':
					if (argc > 3) {
						double fps = atof(argv[2]);
						double fps_base = atof(argv[3]);
						if (fps == 0.0) {
							fps = 1;
							printf("invalid fps,"
							       "forcing 1\n");
						}
						swaptime = fps_base / fps;
						argc -= 2;
						argv += 2;
					}
					else {
						printf("too few arguments for -f (need 2): skipping\n");
					}
					break;
				case 's':
					sfra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
					argc--;
					argv++;
					break;
				case 'e':
					efra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
					argc--;
					argv++;
					break;
				case 'j':
					ps.fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
					swaptime *= ps.fstep;
					argc--;
					argv++;
					break;
				default:
					printf("unknown option '%c': skipping\n", argv[1][1]);
					break;
			}
			argc--;
			argv++;
		}
		else {
			break;
		}
	}

	if (argc > 1) {
		BLI_strncpy(filepath, argv[1], sizeof(filepath));
	}
	else {
		BLI_current_working_dir(filepath, sizeof(filepath));
		BLI_add_slash(filepath);
	}

	if (IMB_isanim(filepath)) {
		/* OCIO_TODO: support different input color spaces */
		anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
		if (anim) {
			ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
			IMB_close_anim(anim);
			anim = NULL;
		}
	}
	else if (!IMB_ispic(filepath)) {
		printf("%s: '%s' not an image file\n", __func__, filepath);
		exit(1);
	}

	if (ibuf == NULL) {
		/* OCIO_TODO: support different input color space */
		ibuf = IMB_loadiffname(filepath, IB_rect, NULL);
	}

	if (ibuf == NULL) {
		printf("%s: '%s' couldn't open\n", __func__, filepath);
		exit(1);
	}

#if 0 //XXX25
	#if !defined(WIN32) && !defined(__APPLE__)
	if (fork()) exit(0);
	#endif
#endif //XXX25

	{

		GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);

		g_WS.ghost_system = GHOST_CreateSystem();
		GHOST_AddEventConsumer(g_WS.ghost_system, consumer);

		playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y);

		/* unified matrix, note it affects offset for drawing */
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
		glMatrixMode(GL_MODELVIEW);
	}

	GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &maxwinx, &maxwiny);

	//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);

	/* initialize the font */
	BLF_init(11, 72);
	ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
	BLF_size(ps.fontid, 11, 72);

	ps.ibufx = ibuf->x;
	ps.ibufy = ibuf->y;
	
	ps.win_x = ps.ibufx;
	ps.win_y = ps.ibufy;

	if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
	if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));

	
	glClearColor(0.1, 0.1, 0.1, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	GHOST_SwapWindowBuffers(g_WS.ghost_window);

	if (sfra == -1 || efra == -1) {
		/* one of the frames was invalid, just use all images */
		sfra = 1;
		efra = MAXFRAME;
	}

	build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);

	for (i = 2; i < argc; i++) {
		BLI_strncpy(filepath, argv[i], sizeof(filepath));
		build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
	}

	IMB_freeImBuf(ibuf);
	ibuf = NULL;

	pupdate_time();
	ptottime = 0;

	/* newly added in 2.6x, without this images never get freed */
#define USE_IMB_CACHE

	while (ps.go) {
		if (ps.pingpong)
			ps.direction = -ps.direction;

		if (ps.direction == 1) {
			ps.picture = picsbase.first;
		}
		else {
			ps.picture = picsbase.last;
		}

		if (ps.picture == NULL) {
			printf("couldn't find pictures\n");
			ps.go = FALSE;
		}
		if (ps.pingpong) {
			if (ps.direction == 1) {
				ps.picture = ps.picture->next;
			}
			else {
				ps.picture = ps.picture->prev;
			}
		}
		if (ptottime > 0.0) ptottime = 0.0;

		while (ps.picture) {
			int hasevent;
#ifndef USE_IMB_CACHE
			if (ibuf != NULL && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
#endif
			if (ps.picture->ibuf) {
				ibuf = ps.picture->ibuf;
			}
			else if (ps.picture->anim) {
				ibuf = IMB_anim_absolute(ps.picture->anim, ps.picture->frame, IMB_TC_NONE, IMB_PROXY_NONE);
			}
			else if (ps.picture->mem) {
				/* use correct colorspace here */
				ibuf = IMB_ibImageFromMemory((unsigned char *) ps.picture->mem, ps.picture->size,
				                             ps.picture->IB_flags, NULL, ps.picture->name);
			}
			else {
				/* use correct colorspace here */
				ibuf = IMB_loadiffname(ps.picture->name, ps.picture->IB_flags, NULL);
			}

			if (ibuf) {

#ifdef USE_IMB_CACHE
				ps.picture->ibuf = ibuf;
#endif

				BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));

				/* why only windows? (from 2.4x) - campbell */
#ifdef _WIN32
				GHOST_SetTitle(g_WS.ghost_window, ps.picture->name);
#endif

				while (pupdate_time()) PIL_sleep_ms(1);
				ptottime -= swaptime;
				playanim_toscreen(&ps, ps.picture, ibuf, ps.fontid, ps.fstep);
			} /* else delete */
			else {
				printf("error: can't play this image type\n");
				exit(0);
			}

			if (ps.once) {
				if (ps.picture->next == NULL) {
					ps.wait2 = TRUE;
				}
				else if (ps.picture->prev == NULL) {
					ps.wait2 = TRUE;
				}
			}

			ps.next_frame = ps.direction;


			while ( (hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0)) || ps.wait2 != 0) {
				if (hasevent) {
					GHOST_DispatchEvents(g_WS.ghost_system);
				}
				/* Note, this still draws for mousemoves on pause */
				if (ps.wait2) {
					if (hasevent) {
						if (ibuf) {
							while (pupdate_time()) PIL_sleep_ms(1);
							ptottime -= swaptime;
							playanim_toscreen(&ps, ps.picture, ibuf, ps.fontid, ps.fstep);
						}
					}
				}
				if (!ps.go) {
					break;
				}
			}

			ps.wait2 = ps.sstep;

			if (ps.wait2 == 0 && ps.stopped == 0) {
				ps.stopped = TRUE;
			}

			pupdate_time();

			if (ps.picture && ps.next_frame) {
				/* always at least set one step */
				while (ps.picture) {
					ps.picture = playanim_step(ps.picture, ps.next_frame);

					if (ps.once && ps.picture != NULL) {
						if (ps.picture->next == NULL) {
							ps.wait2 = TRUE;
						}
						else if (ps.picture->prev == NULL) {
							ps.wait2 = TRUE;
						}
					}

					if (ps.wait2 || ptottime < swaptime || ps.turbo || ps.noskip) break;
					ptottime -= swaptime;
				}
				if (ps.picture == NULL && ps.sstep) {
					ps.picture = playanim_step(ps.picture, ps.next_frame);
				}
			}
			if (ps.go == FALSE) {
				break;
			}
		}
	}
	ps.picture = picsbase.first;
	anim = NULL;
	while (ps.picture) {
		if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
			// to prevent divx crashes
			anim = ps.picture->anim;
			IMB_close_anim(anim);
		}

		if (ps.picture->ibuf) {
			IMB_freeImBuf(ps.picture->ibuf);
		}
		if (ps.picture->mem) {
			MEM_freeN(ps.picture->mem);
		}

		ps.picture = ps.picture->next;
	}

	/* cleanup */
#ifndef USE_IMB_CACHE
	if (ibuf) IMB_freeImBuf(ibuf);
#endif

	BLI_freelistN(&picsbase);
#if 0 // XXX25
	free_blender();
#else
	/* we still miss freeing a lot!,
	 * but many areas could skip initialization too for anim play */
	
	BLF_exit();
#endif
	GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);

	/* early exit, IMB and BKE should be exited only in end */
	if (ps.dropped_file[0]) {
		BLI_strncpy(filepath, ps.dropped_file, sizeof(filepath));
		return filepath;
	}
	
	IMB_exit();
	BKE_images_exit();

	totblock = MEM_get_memory_blocks_in_use();
	if (totblock != 0) {
		/* prints many bAKey, bArgument's which are tricky to fix */
#if 0
		printf("Error Totblock: %d\n", totblock);
		MEM_printmemlist();
#endif
	}
	
	return NULL;
}
示例#6
0
static void build_pict_list(PlayState *ps, char *first, int totframes, int fstep, int fontid)
{
	char *mem, filepath[FILE_MAX];
//	short val;
	PlayAnimPict *picture = NULL;
	struct ImBuf *ibuf = NULL;
	char str[32 + FILE_MAX];
	struct anim *anim;

	if (IMB_isanim(first)) {
		/* OCIO_TODO: support different input color space */
		anim = IMB_open_anim(first, IB_rect, 0, NULL);
		if (anim) {
			int pic;
			ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
			if (ibuf) {
				playanim_toscreen(ps, NULL, ibuf, fontid, fstep);
				IMB_freeImBuf(ibuf);
			}

			for (pic = 0; pic < IMB_anim_get_duration(anim, IMB_TC_NONE); pic++) {
				picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "Pict");
				picture->anim = anim;
				picture->frame = pic;
				picture->IB_flags = IB_rect;
				BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1);
				picture->name = strdup(str);
				BLI_addtail(&picsbase, picture);
			}
		}
		else {
			printf("couldn't open anim %s\n", first);
		}
	}
	else {
		int count = 0;

		BLI_strncpy(filepath, first, sizeof(filepath));

		pupdate_time();
		ptottime = 1.0;

		/* O_DIRECT
		 *
		 * If set, all reads and writes on the resulting file descriptor will
		 * be performed directly to or from the user program buffer, provided
		 * appropriate size and alignment restrictions are met.  Refer to the
		 * F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
		 * information about how to determine the alignment constraints.
		 * O_DIRECT is a Silicon Graphics extension and is only supported on
		 * local EFS and XFS file systems.
		 */

		while (IMB_ispic(filepath) && totframes) {
			size_t size;
			int file;

			file = open(filepath, O_BINARY | O_RDONLY, 0);
			if (file < 0) {
				/* print errno? */
				return;
			}

			picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "picture");
			if (picture == NULL) {
				printf("Not enough memory for pict struct '%s'\n", filepath);
				close(file);
				return;
			}
			size = BLI_file_descriptor_size(file);

			if (size < 1) {
				close(file);
				MEM_freeN(picture);
				return;
			}

			picture->size = size;
			picture->IB_flags = IB_rect;

			if (fromdisk == FALSE) {
				mem = (char *)MEM_mallocN(size, "build pic list");
				if (mem == NULL) {
					printf("Couldn't get memory\n");
					close(file);
					MEM_freeN(picture);
					return;
				}

				if (read(file, mem, size) != size) {
					printf("Error while reading %s\n", filepath);
					close(file);
					MEM_freeN(picture);
					MEM_freeN(mem);
					return;
				}
			}
			else {
				mem = NULL;
			}

			picture->mem = mem;
			picture->name = strdup(filepath);
			close(file);
			BLI_addtail(&picsbase, picture);
			count++;

			pupdate_time();

			if (ptottime > 1.0) {
				/* OCIO_TODO: support different input color space */
				if (picture->mem) {
					ibuf = IMB_ibImageFromMemory((unsigned char *)picture->mem, picture->size,
					                             picture->IB_flags, NULL, picture->name);
				}
				else {
					ibuf = IMB_loadiffname(picture->name, picture->IB_flags, NULL);
				}
				if (ibuf) {
					playanim_toscreen(ps, picture, ibuf, fontid, fstep);
					IMB_freeImBuf(ibuf);
				}
				pupdate_time();
				ptottime = 0.0;
			}

			BLI_newname(filepath, +fstep);

#if 0 // XXX25
			while (qtest()) {
				switch (qreadN(&val)) {
					case ESCKEY:
						if (val) return;
						break;
				}
			}
#endif
			totframes--;
		}
	}
	return;
}
示例#7
0
struct ImBuf *IMB_anim_absolute(struct anim *anim, int position,
                                IMB_Timecode_Type tc,
                                IMB_Proxy_Size preview_size)
{
	struct ImBuf *ibuf = NULL;
	char head[256], tail[256];
	unsigned short digits;
	int pic;
	int filter_y;
	if (anim == NULL) return(NULL);

	filter_y = (anim->ib_flags & IB_animdeinterlace);

	if (anim->curtype == 0) {
		ibuf = anim_getnew(anim);
		if (ibuf == NULL) {
			return(NULL);
		}

		IMB_freeImBuf(ibuf); /* ???? */
		ibuf = NULL;
	}

	if (position < 0) return(NULL);
	if (position >= anim->duration) return(NULL);

	if (preview_size != IMB_PROXY_NONE) {
		struct anim *proxy = IMB_anim_open_proxy(anim, preview_size);

		if (proxy) {
			position = IMB_anim_index_get_frame_index(
			    anim, tc, position);
			return IMB_anim_absolute(
			           proxy, position,
			           IMB_TC_NONE, IMB_PROXY_NONE);
		}
	}

	switch (anim->curtype) {
		case ANIM_SEQUENCE:
			pic = an_stringdec(anim->first, head, tail, &digits);
			pic += position;
			an_stringenc(anim->name, head, tail, digits, pic);
			ibuf = IMB_loadiffname(anim->name, IB_rect, anim->colorspace);
			if (ibuf) {
				anim->curposition = position;
			}
			break;
		case ANIM_MOVIE:
			ibuf = movie_fetchibuf(anim, position);
			if (ibuf) {
				anim->curposition = position;
				IMB_convert_rgba_to_abgr(ibuf);
			}
			break;
#ifdef WITH_AVI
		case ANIM_AVI:
			ibuf = avi_fetchibuf(anim, position);
			if (ibuf)
				anim->curposition = position;
			break;
#endif
#ifdef WITH_QUICKTIME
		case ANIM_QTIME:
			ibuf = qtime_fetchibuf(anim, position);
			if (ibuf) {
				if (ibuf->rect) {
					/* OCIO_TODO: should happen in quicktime module, but it currently doesn't have access
					 *            to color management's internals
					 */
					ibuf->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);
				}

				anim->curposition = position;
			}
			break;
#endif
#ifdef WITH_FFMPEG
		case ANIM_FFMPEG:
			ibuf = ffmpeg_fetchibuf(anim, position, tc);
			if (ibuf)
				anim->curposition = position;
			filter_y = 0; /* done internally */
			break;
#endif
#ifdef WITH_REDCODE
		case ANIM_REDCODE:
			ibuf = redcode_fetchibuf(anim, position);
			if (ibuf) anim->curposition = position;
			break;
#endif
	}

	if (ibuf) {
		if (filter_y) IMB_filtery(ibuf);
		BLI_snprintf(ibuf->name, sizeof(ibuf->name), "%s.%04d", anim->name, anim->curposition + 1);
		
	}
	return(ibuf);
}
示例#8
0
static void index_rebuild_fallback(struct anim * anim,
                                   IMB_Timecode_Type UNUSED(tcs_in_use),
                                   IMB_Proxy_Size proxy_sizes_in_use,
                                   int quality,
                                   short *stop, short *do_update,
                                   float *progress)
{
    int cnt = IMB_anim_get_duration(anim, IMB_TC_NONE);
    int i, pos;
    AviMovie * proxy_ctx[IMB_PROXY_MAX_SLOT];
    char fname[FILE_MAXDIR+FILE_MAXFILE];
    char fname_tmp[FILE_MAXDIR+FILE_MAXFILE];

    memset(proxy_ctx, 0, sizeof(proxy_ctx));

    /* since timecode indices only work with ffmpeg right now,
       don't know a sensible fallback here...

       so no proxies, no game to play...
    */
    if (proxy_sizes_in_use == IMB_PROXY_NONE) {
        return;
    }

    for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
        if (proxy_sizes_in_use & proxy_sizes[i]) {
            char fname[FILE_MAXDIR+FILE_MAXFILE];

            get_proxy_filename(anim, proxy_sizes[i], fname, TRUE);
            BLI_make_existing_file(fname);

            proxy_ctx[i] = alloc_proxy_output_avi(
                               anim, fname,
                               anim->x * proxy_fac[i],
                               anim->y * proxy_fac[i],
                               quality);
        }
    }

    for (pos = 0; pos < cnt; pos++) {
        struct ImBuf * ibuf = IMB_anim_absolute(
                                  anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
        int next_progress = (int) ((double) pos / (double) cnt);

        if (*progress != next_progress) {
            *progress = next_progress;
            *do_update = 1;
        }

        if (*stop) {
            break;
        }

        IMB_flipy(ibuf);

        for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
            if (proxy_sizes_in_use & proxy_sizes[i]) {
                int x = anim->x * proxy_fac[i];
                int y = anim->y * proxy_fac[i];

                struct ImBuf * s_ibuf = IMB_scalefastImBuf(
                                            ibuf, x, y);

                IMB_convert_rgba_to_abgr(s_ibuf);

                AVI_write_frame (proxy_ctx[i], pos,
                                 AVI_FORMAT_RGB32,
                                 s_ibuf->rect, x * y * 4);

                /* note that libavi free's the buffer... */
                s_ibuf->rect = 0;

                IMB_freeImBuf(s_ibuf);
            }
        }
    }

    for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
        if (proxy_sizes_in_use & proxy_sizes[i]) {
            AVI_close_compress (proxy_ctx[i]);
            MEM_freeN (proxy_ctx[i]);

            get_proxy_filename(anim, proxy_sizes[i],
                               fname_tmp, TRUE);
            get_proxy_filename(anim, proxy_sizes[i],
                               fname, FALSE);

            if (*stop) {
                unlink(fname_tmp);
            } else {
                rename(fname_tmp, fname);
            }
        }
    }
}