| 272 | } |
| 273 | |
| 274 | bool WanDiffusion::runVideo(const std::string& prompt, const std::string& outputDir, int width, int height, int frames, |
| 275 | int steps, int seed, float cfgScale, std::function<void(int)> progressCallback) { |
| 276 | AUTOTIME; |
| 277 | if (mModules.size() < 3 || !mModules[0] || !mModules[1] || !mModules[2]) { |
| 278 | MNN_ERROR("Wan modules are not loaded. Please call load() first.\n"); |
| 279 | return false; |
| 280 | } |
| 281 | if (width <= 0 || height <= 0 || frames <= 0) { |
| 282 | MNN_ERROR("Wan video shape must be positive, got width=%d height=%d frames=%d\n", width, height, frames); |
| 283 | return false; |
| 284 | } |
| 285 | const int vaeScaleFactor = 8; |
| 286 | const int transformerPatchSize = 2; |
| 287 | const int spatialAlignment = vaeScaleFactor * transformerPatchSize; |
| 288 | if (width % spatialAlignment != 0 || height % spatialAlignment != 0) { |
| 289 | MNN_ERROR("Wan width and height must be multiples of %d, got %dx%d\n", spatialAlignment, width, height); |
| 290 | return false; |
| 291 | } |
| 292 | if (steps <= 0) { |
| 293 | MNN_PRINT("Warning: Wan steps must be positive; using 1\n"); |
| 294 | steps = 1; |
| 295 | } |
| 296 | |
| 297 | int seqLen = mMaxTextLen; |
| 298 | VARP encoderAttentionMask; |
| 299 | auto encoderHiddenStates = encodePrompt(prompt, &seqLen, &encoderAttentionMask); |
| 300 | if (encoderHiddenStates.get() == nullptr) { |
| 301 | return false; |
| 302 | } |
| 303 | if (mMemoryMode != 1) { |
| 304 | mModules[0].reset(); |
| 305 | MNN::Express::Executor::getGlobalExecutor()->gc(MNN::Express::Executor::FULL); |
| 306 | } |
| 307 | |
| 308 | int latentFrames = std::max(1, (frames + 3) / 4); |
| 309 | int latentH = height / vaeScaleFactor; |
| 310 | int latentW = width / vaeScaleFactor; |
| 311 | int latentChannels = mLatentChannels; |
| 312 | int latentSize = latentChannels * latentFrames * latentH * latentW; |
| 313 | |
| 314 | std::vector<float> noise(latentSize); |
| 315 | int realSeed = seed < 0 ? std::random_device()() : seed; |
| 316 | std::mt19937 rng(realSeed); |
| 317 | std::normal_distribution<float> normal(0.0f, 1.0f); |
| 318 | for (int i = 0; i < latentSize; ++i) { |
| 319 | noise[i] = normal(rng); |
| 320 | } |
| 321 | |
| 322 | VARP latent = _Input({1, latentChannels, latentFrames, latentH, latentW}, NCHW, halide_type_of<float>()); |
| 323 | ::memcpy(latent->writeMap<float>(), noise.data(), noise.size() * sizeof(float)); |
| 324 | |
| 325 | mTimesteps.resize(steps); |
| 326 | if (steps == 1) { |
| 327 | mTimesteps[0] = 1000.0f; |
| 328 | } else { |
| 329 | float shift = 3.0f; |
| 330 | for (int i = 0; i < steps; ++i) { |
| 331 | float tLinear = 1.0f + i * (0.001f - 1.0f) / (float)(steps - 1); |
nothing calls this directly
no test coverage detected