__unused JNIEXPORT jlong JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_renderFrame(JNIEnv *env, jclass __unused handleClass, jlong gifInfo, jobject jbitmap) {
	GifInfo *info = (GifInfo *) (intptr_t) gifInfo;
	if (info == NULL)
		return -1;

	long renderStartTime = getRealTime();
	void *pixels;
	if (lockPixels(env, jbitmap, info, &pixels) != 0) {
		return 0;
	}
	DDGifSlurp(info, true, false);
	if (info->currentIndex == 0) {
		prepareCanvas(pixels, info);
	}
	const uint_fast32_t frameDuration = getBitmap(pixels, info);
	unlockPixels(env, jbitmap);
	return calculateInvalidationDelay(info, renderStartTime, frameDuration);
}
示例#2
0
文件: surface.c 项目: zetbrush/Stuff
__unused JNIEXPORT void JNICALL
Java_com_picsart_studio_gifencoder_GifInfoHandle_bindSurface(JNIEnv *env, jclass __unused handleClass, jlong gifInfo,
                                                    jobject jsurface, jlongArray savedState, jboolean isOpaque) {

    GifInfo *info = (GifInfo *) (intptr_t) gifInfo;
    if (info->surfaceDescriptor == NULL) {
        info->surfaceDescriptor = malloc(sizeof(SurfaceDescriptor));
        if (!initSurfaceDescriptor(info->surfaceDescriptor, env)) {
            free(info->surfaceDescriptor);
            info->surfaceDescriptor = NULL;
            return;
        }
    }

    POLL_TYPE eftd_ctr;
    int pollResult;

    while (1) {
        pollResult = poll(&info->surfaceDescriptor->eventPollFd, 1, 0);
        if (pollResult == 0)
            break;
        else if (pollResult > 0) {
            if (read(info->surfaceDescriptor->eventPollFd.fd, &eftd_ctr, POLL_TYPE_SIZE) != POLL_TYPE_SIZE) {
                throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "Read on flushing failed");
                return;
            }
        }
        else {
            throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "Poll on flushing failed");
            return;
        }
    }

    const int32_t windowFormat = isOpaque == JNI_TRUE ? WINDOW_FORMAT_RGBX_8888 : WINDOW_FORMAT_RGBA_8888;
    info->isOpaque = isOpaque;

    struct ANativeWindow *window = ANativeWindow_fromSurface(env, jsurface);
    if (ANativeWindow_setBuffersGeometry(window, (int32_t) info->gifFilePtr->SWidth,
                                         (int32_t) info->gifFilePtr->SHeight,
                                         windowFormat) != 0) {
        ANativeWindow_release(window);
        throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "Buffers geometry setting failed");
        return;
    }

    struct ANativeWindow_Buffer buffer = {.bits =NULL};
    void *oldBufferBits;

    if (ANativeWindow_lock(window, &buffer, NULL) != 0) {
        ANativeWindow_release(window);
        throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "Window lock failed");
        return;
    }
    const size_t bufferSize = buffer.stride * buffer.height * sizeof(argb);

    info->stride = buffer.stride;
    long invalidationDelayMillis;
    if (info->surfaceDescriptor->surfaceBackupPtr) {
        memcpy(buffer.bits, info->surfaceDescriptor->surfaceBackupPtr, bufferSize);
        invalidationDelayMillis = 0;
        info->surfaceDescriptor->renderHelper = 1;
        info->surfaceDescriptor->slurpHelper = 0;
    }
    else {
        if (savedState != NULL){
            invalidationDelayMillis = restoreSavedState(info, env, savedState, buffer.bits);
            if (invalidationDelayMillis <0)
                invalidationDelayMillis =0;
        }
        else
            invalidationDelayMillis = 0;
        info->surfaceDescriptor->renderHelper = 0;
        info->surfaceDescriptor->slurpHelper = 1;
    }

    info->lastFrameRemainder = -1;
    ANativeWindow_unlockAndPost(window);

    if (info->loopCount != 0 && info->currentLoop == info->loopCount) {
        ANativeWindow_release(window);
        pollResult = poll(&info->surfaceDescriptor->eventPollFd, 1, -1);
        if (pollResult < 0) {
            throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "animation end poll failed");
        }
        return;
    }

    pthread_t thread;
    if (pthread_create(&thread, NULL, slurp, info) != 0) {
        ANativeWindow_release(window);
        throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "pthread_create failed");
        return;
    }

    while (1) {
        pollResult = poll(&info->surfaceDescriptor->eventPollFd, 1, (int) invalidationDelayMillis);
        long renderingStartTime = getRealTime();

        if (pollResult < 0) {
            throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "Poll failed");
            break;
        }
        else if (pollResult > 0) {
            if (info->surfaceDescriptor->surfaceBackupPtr == NULL) {
                info->surfaceDescriptor->surfaceBackupPtr = malloc(bufferSize);
                if (info->surfaceDescriptor->surfaceBackupPtr == NULL) {
                    throwException(env, OUT_OF_MEMORY_ERROR, OOME_MESSAGE);
                    break;
                }
            }
            memcpy(info->surfaceDescriptor->surfaceBackupPtr, buffer.bits, bufferSize);
            break;
        }
        oldBufferBits = buffer.bits;
        THROW_AND_BREAK_ON_NONZERO_RESULT(ANativeWindow_lock(window, &buffer, NULL), "Window lock failed");

        if (info->currentIndex == 0)
            prepareCanvas(buffer.bits, info);
        else
            memcpy(buffer.bits, oldBufferBits, bufferSize);

        pthread_mutex_lock(&info->surfaceDescriptor->renderMutex);
        while (info->surfaceDescriptor->renderHelper == 0) {
            pthread_cond_wait(&info->surfaceDescriptor->renderCond, &info->surfaceDescriptor->renderMutex);
        }
        info->surfaceDescriptor->renderHelper = 0;
        pthread_mutex_unlock(&info->surfaceDescriptor->renderMutex);

        const uint_fast32_t frameDuration = getBitmap(buffer.bits, info);

        pthread_mutex_lock(&info->surfaceDescriptor->slurpMutex);
        info->surfaceDescriptor->slurpHelper = 1;
        pthread_cond_signal(&info->surfaceDescriptor->slurpCond);
        pthread_mutex_unlock(&info->surfaceDescriptor->slurpMutex);

        ANativeWindow_unlockAndPost(window);

        invalidationDelayMillis = calculateInvalidationDelay(info, renderingStartTime, frameDuration);

        if (info->lastFrameRemainder >= 0) {
            invalidationDelayMillis = info->lastFrameRemainder;
            info->lastFrameRemainder = -1;
        }
    }

    ANativeWindow_release(window);
    pthread_mutex_lock(&info->surfaceDescriptor->slurpMutex);
    info->surfaceDescriptor->slurpHelper = 2;
    pthread_cond_signal(&info->surfaceDescriptor->slurpCond);
    pthread_mutex_unlock(&info->surfaceDescriptor->slurpMutex);
    THROW_ON_NONZERO_RESULT(pthread_join(thread, NULL), "join failed");
}
示例#3
0
__unused JNIEXPORT void JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_bindSurface(JNIEnv *env, jclass __unused handleClass, jlong gifInfo,
                                                    jobject jsurface, jlongArray savedState) {
	GifInfo *info = (GifInfo *) (intptr_t) gifInfo;
	SurfaceDescriptor *descriptor = info->frameBufferDescriptor;
	if (descriptor == NULL) {
		descriptor = malloc(sizeof(SurfaceDescriptor));
		if (descriptor == NULL) {
			throwException(env, OUT_OF_MEMORY_ERROR, OOME_MESSAGE);
			return;
		}
		descriptor->eventPollFd.events = POLL_IN;
		descriptor->eventPollFd.fd = eventfd(0, 0);
		if (descriptor->eventPollFd.fd == -1) {
			throwException(env, RUNTIME_EXCEPTION_ERRNO, "Eventfd creation failed ");
			free(descriptor);
			return;
		}
		errno = pthread_cond_init(&descriptor->slurpCond, NULL);
		THROW_ON_NONZERO_RESULT(errno, "Slurp condition variable initialization failed ");
		errno = pthread_cond_init(&descriptor->renderCond, NULL);
		THROW_ON_NONZERO_RESULT(errno, "Render condition variable initialization failed ");
		errno = pthread_mutex_init(&descriptor->slurpMutex, NULL);
		THROW_ON_NONZERO_RESULT(errno, "Slurp mutex initialization failed ");
		errno = pthread_mutex_init(&descriptor->renderMutex, NULL);
		THROW_ON_NONZERO_RESULT(errno, "Render mutex initialization failed ");
		descriptor->frameBuffer = NULL;
		info->frameBufferDescriptor = descriptor;
		info->destructor = releaseSurfaceDescriptor;
	}

	eventfd_t eventValue;
	int pollResult;

	while (1) {
		pollResult = TEMP_FAILURE_RETRY(poll(&descriptor->eventPollFd, 1, 0));
		if (pollResult == 0)
			break;
		else if (pollResult > 0) {
			const int readResult = TEMP_FAILURE_RETRY(eventfd_read(descriptor->eventPollFd.fd, &eventValue));
			if (readResult != 0) {
				throwException(env, RUNTIME_EXCEPTION_ERRNO, "Could not read from eventfd ");
				return;
			}
		}
		else {
			throwException(env, RUNTIME_EXCEPTION_ERRNO, "Could not poll on eventfd ");
			return;
		}
	}

	const int32_t windowFormat = info->isOpaque ? WINDOW_FORMAT_RGBX_8888 : WINDOW_FORMAT_RGBA_8888;
	struct ANativeWindow *window = ANativeWindow_fromSurface(env, jsurface);
	GifFileType *const gifFilePtr = info->gifFilePtr;
	if (ANativeWindow_setBuffersGeometry(window, (int32_t) gifFilePtr->SWidth, (int32_t) gifFilePtr->SHeight, windowFormat) != 0) {
		ANativeWindow_release(window);
		throwException(env, RUNTIME_EXCEPTION_ERRNO, "Buffers geometry setting failed ");
		return;
	}

	struct ANativeWindow_Buffer buffer = {.bits =NULL};
	void *oldBufferBits;

	if (ANativeWindow_lock(window, &buffer, NULL) != 0) {
#ifdef DEBUG
		LOGE("Window lock failed %d", errno);
#endif
		ANativeWindow_release(window);
		return;
	}
	const size_t bufferSize = buffer.stride * buffer.height * sizeof(argb);

	info->stride = buffer.stride;
	long long invalidationDelayMillis;
	if (descriptor->frameBuffer) {
		memcpy(buffer.bits, descriptor->frameBuffer, bufferSize);
		invalidationDelayMillis = 0;
		descriptor->renderHelper = 1;
		descriptor->slurpHelper = 0;
	} else {
		if (savedState != NULL) {
			invalidationDelayMillis = restoreSavedState(info, env, savedState, buffer.bits);
			if (invalidationDelayMillis < 0)
				invalidationDelayMillis = 0;
		} else
			invalidationDelayMillis = 0;
		descriptor->renderHelper = 0;
		descriptor->slurpHelper = 1;
	}

	info->lastFrameRemainder = -1;
	ANativeWindow_unlockAndPost(window);

	if (info->loopCount != 0 && info->currentLoop == info->loopCount) {
		ANativeWindow_release(window);
		pollResult = TEMP_FAILURE_RETRY(poll(&descriptor->eventPollFd, 1, -1));
		if (pollResult < 0) {
			throwException(env, RUNTIME_EXCEPTION_ERRNO, "Animation end poll failed ");
		}
		return;
	}

	errno = pthread_create(&descriptor->slurpThread, NULL, slurp, info);
	if (errno != 0) {
		throwException(env, RUNTIME_EXCEPTION_ERRNO, "Slurp thread creation failed ");
		ANativeWindow_release(window);
		return;
	}

	while (1) {
		pollResult = TEMP_FAILURE_RETRY(poll(&descriptor->eventPollFd, 1, (int) invalidationDelayMillis));
		long renderingStartTime = getRealTime();

		if (pollResult < 0) {
			throwException(env, RUNTIME_EXCEPTION_ERRNO, "Display loop poll failed ");
			break;
		} else if (pollResult > 0) {
			if (descriptor->frameBuffer == NULL) {
				descriptor->frameBuffer = malloc(bufferSize);
				if (descriptor->frameBuffer == NULL) {
					throwException(env, OUT_OF_MEMORY_ERROR, OOME_MESSAGE);
					break;
				}
			}
			memcpy(descriptor->frameBuffer, buffer.bits, bufferSize);
			break;
		}
		oldBufferBits = buffer.bits;

		struct ARect *dirtyRectPtr;
		if (info->currentIndex == 0) {
			dirtyRectPtr = NULL;
		} else {
			const GifImageDesc imageDesc = gifFilePtr->SavedImages[info->currentIndex].ImageDesc;
			struct ARect dirtyRect = {
					.left = imageDesc.Left,
					.top = imageDesc.Top,
					.right = imageDesc.Left + imageDesc.Width,
					.bottom = imageDesc.Top + imageDesc.Height
			};
			dirtyRectPtr = &dirtyRect;
		}
		if (ANativeWindow_lock(window, &buffer, dirtyRectPtr) != 0) {
#ifdef DEBUG
			LOGE("Window lock failed %d", errno);
#endif
			break;
		}

		if (info->currentIndex == 0)
			prepareCanvas(buffer.bits, info);
		else
			memcpy(buffer.bits, oldBufferBits, bufferSize);

		pthread_mutex_lock(&descriptor->renderMutex);
		while (descriptor->renderHelper == 0) {
			pthread_cond_wait(&descriptor->renderCond, &descriptor->renderMutex);
		}
		descriptor->renderHelper = 0;
		pthread_mutex_unlock(&descriptor->renderMutex);

		const uint_fast32_t frameDuration = getBitmap(buffer.bits, info);

		pthread_mutex_lock(&descriptor->slurpMutex);
		descriptor->slurpHelper = 1;
		pthread_cond_signal(&descriptor->slurpCond);
		pthread_mutex_unlock(&descriptor->slurpMutex);

		ANativeWindow_unlockAndPost(window);

		invalidationDelayMillis = calculateInvalidationDelay(info, renderingStartTime, frameDuration);

		if (info->lastFrameRemainder >= 0) {
			invalidationDelayMillis = info->lastFrameRemainder;
			info->lastFrameRemainder = -1;
		}
	}

	ANativeWindow_release(window);
	pthread_mutex_lock(&descriptor->slurpMutex);
	descriptor->slurpHelper = 2;
	pthread_cond_signal(&descriptor->slurpCond);
	pthread_mutex_unlock(&descriptor->slurpMutex);
	errno = pthread_join(descriptor->slurpThread, NULL);
	THROW_ON_NONZERO_RESULT(errno, "Slurp thread join failed");
}

__unused JNIEXPORT void JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_postUnbindSurface(JNIEnv *env, jclass __unused handleClass, jlong gifInfo) {
	GifInfo *info = (GifInfo *) (intptr_t) gifInfo;
	if (info == NULL || info->frameBufferDescriptor == NULL) {
		return;
	}
	SurfaceDescriptor const *descriptor = info->frameBufferDescriptor;
	const int writeResult = TEMP_FAILURE_RETRY(eventfd_write(descriptor->eventPollFd.fd, 1));
	if (writeResult != 0 && errno != EBADF) {
		throwException(env, RUNTIME_EXCEPTION_ERRNO, "Could not write to eventfd ");
	}
}