private async Task <LogItem> ProcessItem(EncodeServer server, QueueItem src) { DateTime now = DateTime.Now; if (File.Exists(src.Path) == false) { return(FailLogItem(src.Path, "入力ファイルが見つかりません", now, now)); } bool isMp4 = src.Path.ToLower().EndsWith(".mp4"); string dstpath = Path.Combine(encoded, Path.GetFileName(src.Path)); string srcpath = src.Path; string localsrc = null; string localdst = dstpath; // ハッシュがある(ネットワーク経由)の場合はローカルにコピー if (hashList != null) { localsrc = tmpBase + "-in" + Path.GetExtension(srcpath); string name = Path.GetFileName(srcpath); if (hashList.ContainsKey(name) == false) { return(FailLogItem(src.Path, "入力ファイルのハッシュがありません", now, now)); } byte[] hash = await HashUtil.CopyWithHash(srcpath, localsrc); var refhash = hashList[name]; if (hash.SequenceEqual(refhash) == false) { File.Delete(localsrc); return(FailLogItem(src.Path, "コピーしたファイルのハッシュが一致しません", now, now)); } srcpath = localsrc; localdst = tmpBase + "-out.mp4"; } string json = Path.Combine( Path.GetDirectoryName(localdst), Path.GetFileNameWithoutExtension(localdst)) + "-enc.json"; string logpath = Path.Combine( Path.GetDirectoryName(dstpath), Path.GetFileNameWithoutExtension(dstpath)) + "-enc.log"; string args = server.MakeAmatsukazeArgs(isMp4, srcpath, localdst, json); string exename = server.appData.setting.AmatsukazePath; Util.AddLog(id, "エンコード開始: " + src.Path); Util.AddLog(id, "Args: " + exename + " " + args); DateTime start = DateTime.Now; var psi = new ProcessStartInfo(exename, args) { UseShellExecute = false, WorkingDirectory = Directory.GetCurrentDirectory(), RedirectStandardError = true, RedirectStandardOutput = true, RedirectStandardInput = false, CreateNoWindow = true }; IntPtr affinityMask = new IntPtr((long)server.affinityCreator.GetMask(id)); Util.AddLog(id, "AffinityMask: " + affinityMask.ToInt64()); int exitCode = -1; logText.Clear(); try { using (var p = Process.Start(psi)) { // アフィニティを設定 p.ProcessorAffinity = affinityMask; p.PriorityClass = ProcessPriorityClass.BelowNormal; process = p; using (logWriter = File.Create(logpath)) { await Task.WhenAll( RedirectOut(server, p.StandardOutput.BaseStream), RedirectOut(server, p.StandardError.BaseStream), Task.Run(() => p.WaitForExit())); } exitCode = p.ExitCode; } } catch (Win32Exception w32e) { Util.AddLog(id, "Amatsukazeプロセス起動に失敗"); throw w32e; } finally { logWriter = null; process = null; } DateTime finish = DateTime.Now; if (hashList != null) { File.Delete(localsrc); } if (exitCode == 0) { // 成功ならログを整形したテキストに置き換える using (var fs = new StreamWriter(File.Create(logpath), Encoding.Default)) { foreach (var str in logText.TextLines) { fs.WriteLine(str); } } } // ログファイルを専用フォルダにコピー if (File.Exists(logpath)) { string logbase = server.GetLogFileBase(start); Directory.CreateDirectory(Path.GetDirectoryName(logbase)); string dstlog = logbase + ".txt"; File.Copy(logpath, dstlog); if (File.Exists(json)) { string dstjson = logbase + ".json"; File.Move(json, dstjson); json = dstjson; } } if (exitCode == 0) { // 成功 var log = LogFromJson(isMp4, json, start, finish); // ハッシュがある(ネットワーク経由)の場合はリモートにコピー if (hashList != null) { log.SrcPath = src.Path; string outbase = Path.GetDirectoryName(dstpath) + "\\" + Path.GetFileNameWithoutExtension(dstpath); for (int i = 0; i < log.OutPath.Count; ++i) { string outext = Path.GetExtension(log.OutPath[i]); string outpath = outbase + ((i == 0) ? outext : ("-" + i + outext)); var hash = await HashUtil.CopyWithHash(log.OutPath[i], outpath); string name = Path.GetFileName(outpath); HashUtil.AppendHash(Path.Combine(encoded, "_mp4.hash"), name, hash); File.Delete(log.OutPath[i]); log.OutPath[i] = outpath; } } return(log); } else { // 失敗 return(FailLogItem(src.Path, "Amatsukaze.exeはコード" + exitCode + "で終了しました。", start, finish)); } }
// アイテムのProfileNameからプロファイルを決定して、 // オプションでwaits!=nullのときはクライアントに通知 // 戻り値: プロファイルが変更された場合(結果、エラーになった場合も含む) private bool UpdateProfileItem(QueueItem item, List <Task> waits) { var getResult = server.GetProfile(item, item.ProfileName); var profile = (getResult != null) ? ServerSupport.DeepCopy(getResult.Profile) : server.PendingProfile; var priority = (getResult != null && getResult.Priority > 0) ? getResult.Priority : item.Priority; if (item.Profile == null || item.Profile.Name != profile.Name || item.Profile.LastUpdate != profile.LastUpdate || item.Priority != priority) { // 変更 item.Profile = profile; item.Priority = priority; // ハッシュリスト取得 if (profile != server.PendingProfile && // ペンディングの場合は決定したときに実行される item.IsSeparateHashRequired) { var hashpath = Path.GetDirectoryName(item.SrcPath) + ".hash"; if (hashCache.ContainsKey(hashpath) == false) { if (File.Exists(hashpath) == false) { item.State = QueueState.LogoPending; item.FailReason = "ハッシュファイルがありません: " + hashpath; return(true); } else { try { hashCache.Add(hashpath, new DirHash() { DirPath = hashpath, HashDict = HashUtil.ReadHashFile(hashpath) }); } catch (IOException e) { item.State = QueueState.LogoPending; item.FailReason = "ハッシュファイルの読み込みに失敗: " + e.Message; return(true); } } } var cacheItem = hashCache[hashpath]; var filename = item.FileName; if (cacheItem.HashDict.ContainsKey(filename) == false) { item.State = QueueState.LogoPending; item.FailReason = "ハッシュファイルにこのファイルのハッシュがありません"; return(true); } item.Hash = cacheItem.HashDict[filename]; } server.ReScheduleQueue(); UpdateQueueItem(item, waits); waits?.Add(ClientQueueUpdate(new QueueUpdate() { Type = UpdateType.Add, Item = item })); return(true); } return(false); }
private async Task StartEncode() { NowEncoding = true; // 待たなくてもいいタスクリスト var waitList = new List <Task>(); // 状態を更新 waitList.Add(RequestState()); try { while (queue.Count > 0) { // 不正な設定は強制的に直しちゃう if (appData.setting.NumParallel <= 0 || appData.setting.NumParallel > 64) { appData.setting.NumParallel = 1; } int numParallel = appData.setting.NumParallel; // 足りない場合は追加 while (taskList.Count < numParallel) { taskList.Add(new EncodeTask() { id = taskList.Count, consoleText = new ConsoleText(500), logText = new ConsoleText(1 * 1024 * 1024) }); } // 多すぎる場合は削除 while (taskList.Count > numParallel) { taskList.RemoveAt(taskList.Count - 1); } affinityCreator.NumProcess = numParallel; var dir = queue[0]; Dictionary <string, byte[]> hashList = null; if (dir.Path.StartsWith("\\\\")) { var hashpath = dir.Path + ".hash"; if (File.Exists(hashpath) == false) { throw new IOException("ハッシュファイルがありません: " + hashpath + "\r\n" + "ネットワーク経由の場合はBatchHashCheckerによるハッシュファイル生成が必須です。"); } hashList = HashUtil.ReadHashFile(hashpath); } Task[] tasks = new Task[numParallel]; for (int i = 0; i < numParallel; ++i) { taskList[i].hashList = hashList; taskList[i].tmpBase = Util.CreateTmpFile(appData.setting.WorkPath); tasks[i] = taskList[i].ProcessDiretoryItem(this, dir); } await Task.WhenAll(tasks); for (int i = 0; i < numParallel; ++i) { File.Delete(taskList[i].tmpBase); } if (encodePaused) { break; } queue.Remove(dir); waitList.Add(client.OnQueueUpdate(new QueueUpdate() { Type = UpdateType.Remove, DirPath = dir.Path, })); } } catch (Exception e) { waitList.Add(AddEncodeLog( "エラーでエンコードが停止しました: " + e.Message)); } NowEncoding = false; // 状態を更新 waitList.Add(RequestState()); await Task.WhenAll(waitList.ToArray()); }