Beispiel #1
0
        // アイテムの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);
        }
Beispiel #2
0
 private void ResetStateItem(QueueItem item, List <Task> waits)
 {
     item.Reset();
     UpdateQueueItem(item, waits);
     waits.Add(NotifyQueueItemUpdate(item));
 }
Beispiel #3
0
        public async Task AddQueue(AddQueueRequest req)
        {
            List <Task> waits = new List <Task>();

            addQueueCanceled = false;

            // ユーザ操作でない場合はログを記録する
            bool enableLog = (req.Mode == ProcMode.AutoBatch);

            if (req.Outputs.Count == 0)
            {
                await server.NotifyError("出力が1つもありません", enableLog);

                return;
            }

            // 既に追加されているファイルは除外する
            // バッチのときは全ファイルが対象だが、バッチじゃなければバッチのみが対象
            var ignores = req.IsBatch ? Queue : Queue.Where(t => t.IsBatch);

            var ignoreSet = new HashSet <string>(
                ignores.Where(item => item.IsActive)
                .Select(item => item.SrcPath));

            var items = ((req.Targets != null)
                ? req.Targets
                : Directory.GetFiles(req.DirPath)
                         .Where(s =>
            {
                string lower = s.ToLower();
                return(lower.EndsWith(".ts") || lower.EndsWith(".m2t"));
            })
                         .Select(f => new AddQueueItem()
            {
                Path = f
            }))
                        .Where(f => !ignoreSet.Contains(f.Path)).ToList();

            waits.Add(WriteLine("" + items.Count + "件を追加処理します"));

            var map      = server.ServiceMap;
            var numItems = 0;
            var progress = 0;

            // TSファイル情報を読む
            foreach (var additem in items)
            {
                waits.Add(WriteLine("(" + (++progress) + "/" + items.Count + ") " + Path.GetFileName(additem.Path) + " を処理中"));

                using (var info = new TsInfo(amtcontext))
                {
                    var failReason = "";
                    var addItems   = new List <QueueItem>();
                    if (await Task.Run(() => info.ReadFile(additem.Path)) == false)
                    {
                        failReason = "TS情報取得に失敗: " + amtcontext.GetError();
                    }
                    else
                    {
                        failReason = "TSファイルに映像が見つかりませんでした";
                        var list      = info.GetProgramList();
                        var videopids = new List <int>();
                        int numFiles  = 0;
                        for (int i = 0; i < list.Length; ++i)
                        {
                            var prog = list[i];
                            if (prog.HasVideo &&
                                videopids.Contains(prog.VideoPid) == false)
                            {
                                videopids.Add(prog.VideoPid);

                                var serviceName = "不明";
                                var tsTime      = DateTime.MinValue;
                                if (info.HasServiceInfo)
                                {
                                    var service = info.GetServiceList().Where(s => s.ServiceId == prog.ServiceId).FirstOrDefault();
                                    if (service.ServiceId != 0)
                                    {
                                        serviceName = service.ServiceName;
                                    }
                                    tsTime = info.GetTime();
                                }

                                var outname = Path.GetFileNameWithoutExtension(additem.Path);
                                if (numFiles > 0)
                                {
                                    outname += "-マルチ" + numFiles;
                                }

                                Debug.Print("解析完了: " + additem.Path);

                                foreach (var outitem in req.Outputs)
                                {
                                    var genre = prog.Content.Select(s => ServerSupport.GetGenre(s)).ToList();

                                    var item = new QueueItem()
                                    {
                                        Id          = nextItemId++,
                                        Mode        = req.Mode,
                                        SrcPath     = additem.Path,
                                        Hash        = additem.Hash,
                                        DstPath     = outitem.DstPath + "\\" + outname,
                                        ServiceId   = prog.ServiceId,
                                        ImageWidth  = prog.Width,
                                        ImageHeight = prog.Height,
                                        TsTime      = tsTime,
                                        ServiceName = serviceName,
                                        EventName   = prog.EventName,
                                        State       = QueueState.LogoPending,
                                        Priority    = outitem.Priority,
                                        AddTime     = DateTime.Now,
                                        ProfileName = outitem.Profile,
                                        Genre       = genre,
                                        Tags        = new List <string>()
                                    };

                                    if (item.IsOneSeg)
                                    {
                                        item.State      = QueueState.PreFailed;
                                        item.FailReason = "映像が小さすぎます(" + prog.Width + "," + prog.Height + ")";
                                    }
                                    else
                                    {
                                        // ロゴファイルを探す
                                        if (req.Mode != ProcMode.DrcsCheck && map.ContainsKey(item.ServiceId) == false)
                                        {
                                            // 新しいサービスを登録
                                            waits.Add(server.AddService(new ServiceSettingElement()
                                            {
                                                ServiceId    = item.ServiceId,
                                                ServiceName  = item.ServiceName,
                                                LogoSettings = new List <LogoSetting>()
                                            }));
                                        }

                                        // 追加時バッチ
                                        if (string.IsNullOrEmpty(req.AddQueueBat) == false)
                                        {
                                            waits.Add(WriteLine("追加時バッチ起動"));
                                            using (var scriptExecuter = new UserScriptExecuter()
                                            {
                                                Server = server,
                                                Phase = ScriptPhase.OnAdd,
                                                ScriptPath = server.GetBatDirectoryPath() + "\\" + req.AddQueueBat,
                                                Item = item,
                                                Prog = prog,
                                                OnOutput = WriteTextBytes
                                            })
                                            {
                                                process = scriptExecuter;
                                                await scriptExecuter.Execute();

                                                process = null;
                                            }

                                            if (addQueueCanceled)
                                            {
                                                break;
                                            }
                                        }

                                        ++numFiles;
                                    }

                                    addItems.Add(item);
                                }
                            }
                        }
                    }

                    if (addQueueCanceled)
                    {
                        break;
                    }

                    if (addItems.Count == 0)
                    {
                        // アイテムが1つもないときはエラー項目として追加
                        foreach (var outitem in req.Outputs)
                        {
                            bool isAuto      = false;
                            var  profileName = ServerSupport.ParseProfileName(outitem.Profile, out isAuto);
                            var  profile     = isAuto ? null : ServerSupport.DeepCopy(server.GetProfile(profileName));

                            var item = new QueueItem()
                            {
                                Id          = nextItemId++,
                                Mode        = req.Mode,
                                Profile     = profile,
                                SrcPath     = additem.Path,
                                Hash        = additem.Hash,
                                DstPath     = "",
                                ServiceId   = -1,
                                ImageWidth  = -1,
                                ImageHeight = -1,
                                TsTime      = DateTime.MinValue,
                                ServiceName = "不明",
                                State       = QueueState.PreFailed,
                                FailReason  = failReason,
                                AddTime     = DateTime.Now,
                                ProfileName = outitem.Profile,
                                Tags        = new List <string>()
                            };

                            addItems.Add(item);
                        }
                    }

                    // 1ソースファイルに対するaddはatomicに実行したいので、
                    // このループではawaitしないこと
                    foreach (var item in addItems)
                    {
                        if (item.State != QueueState.PreFailed)
                        {
                            // プロファイルを設定
                            UpdateProfileItem(item, null);
                        }
                        // 追加
                        item.Order = Queue.Count;
                        Queue.Add(item);
                        // まずは内部だけで状態を更新
                        UpdateQueueItem(item, null);
                        // 状態が決まったらクライアント側に追加通知
                        waits.Add(ClientQueueUpdate(new QueueUpdate()
                        {
                            Type = UpdateType.Add,
                            Item = item
                        }));
                    }

                    numItems += addItems.Count;

                    UpdateProgress();
                    waits.Add(server.RequestState());
                }

                if (addQueueCanceled)
                {
                    break;
                }
            }

            if (addQueueCanceled)
            {
                waits.Add(WriteLine("キャンセルされました"));
            }

            waits.Add(WriteLine("" + numItems + "件追加しました"));

            if (addQueueCanceled == false && numItems == 0)
            {
                waits.Add(server.NotifyError(
                              "エンコード対象ファイルがありませんでした。パス:" + req.DirPath, enableLog));

                await Task.WhenAll(waits);

                return;
            }
            else
            {
                waits.Add(server.NotifyMessage("" + numItems + "件追加しました", false));
            }

            if (req.Mode != ProcMode.AutoBatch)
            {
                // 最後に使った設定を記憶しておく
                server.LastUsedProfile = req.Outputs[0].Profile;
                server.AddOutPathHistory(req.Outputs[0].DstPath);
                server.LastAddQueueBat = req.AddQueueBat;
                waits.Add(server.RequestUIState());
            }

            waits.Add(server.RequestFreeSpace());

            await Task.WhenAll(waits);
        }
Beispiel #4
0
 private static bool IsInConsistent(QueueItem item, int priority, int key)
 {
     return(item.Priority != priority ||
            key != item.Profile.ReqResources[EncodePhase].Canonical());
 }
Beispiel #5
0
 // アイテムを1つだけ強制的に開始する
 public void ForceStart(QueueItem item)
 {
     EnsureNumWorkers(running.Count + parking.Count + 1);
     ActivateOneWorker(item);
 }
Beispiel #6
0
            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));
                }
            }