예제 #1
0
        /**
         * ターゲットの動画ファイルをセットする
         */
        public async void SetSource(StorageFile source)
        {
            Reset();

            if (null == source)
            {
                return;
            }
            mPlayer.SetSource(source);


            try
            {
                mClip = await MediaClip.CreateFromFileAsync(source);

                mTrimmingSlider.TotalRange = mClip.OriginalDuration.TotalMilliseconds;
                await mExtractor.ExtractAsync(mClip, (s, i, img) =>
                {
                    mFrameListView.Frames[i] = img;
                },
                                              (s, img) =>
                {
                    mFrameListView.FrameListHeight = mExtractor.ThumbnailHeight;
                    for (int i = 0; i < mExtractor.FrameCount; i++)
                    {
                        mFrameListView.Frames.Add(img);
                    }
                });
            }
            catch (Exception e)
            {
                CmLog.error("WvvFrameSelectorView.SetSource", e);
                Error.SetError(e);
            }
        }
예제 #2
0
 /**
  * MediaOpenedイベントのハンドラ
  */
 private async void OnOpened(MediaPlayer sender, object args)
 {
     Opened = true;
     if (null != OwnerView)
     {
         CmLog.debug("WvvMediaLoader.OnOpened: MediaOpened");
         await terminate(sender);
     }
 }
예제 #3
0
        /**
         * 動画ファイルをロードして、フレームサムネイルを抽出する。
         */
        private async void LoadMediaSource(StorageFile source)
        {
            Ready = false;

            //
            Error.Reset();
            mPlayer.Source = null;
            mPreviewing    = false;
            mTrimmingSlider.Reset();
            mFrameListView.Reset();
            mExtractor.Cancel();
            mFrameListView.ShowCurrentTick = false;

            mComposition.Clips.Clear();
            if (null != source)
            {
                mOriginalSource = MediaSource.CreateFromStorageFile(source);
                var loader = await WvvMediaLoader.LoadAsync(mPlayer, mOriginalSource, this);

                if (loader.Opened)
                {
                    TotalRange = loader.TotalRange;
                    VideoSize  = loader.VideoSize;

                    try
                    {
                        var clip = await MediaClip.CreateFromFileAsync(source);

                        mComposition.Clips.Add(clip.Clone());
                        Ready = true;
                        await mExtractor.ExtractAsync(clip, (s, i, img) =>
                        {
                            mFrameListView.Frames[i] = img;
                        },
                                                      (s, img) =>
                        {
                            mFrameListView.FrameListHeight = mExtractor.ThumbnailHeight;
                            for (int i = 0; i < ThumbnailCount; i++)
                            {
                                mFrameListView.Frames.Add(img);
                            }
                            mFrameListView.ShowCurrentTick = true;
                        });
                    }
                    catch (Exception e)
                    {
                        CmLog.error(e, "WvvTrimmingView.LoadMediaSource: Error");
                        Error.SetError(e);
                    }
                }
                else // not opened.
                {
                    Error.CopyFrom(loader.Error);
                }
            }
        }
예제 #4
0
        /**
         * フレームの抽出処理を開始
         *
         * @param   clip        ソースを保持したMediaClip
         * @param   extracted   取得したフレーム画像をコールバックするハンドラ
         */
        public async Task <bool> ExtractAsync(MediaClip clip, OnThumbnailExtractedHandler extracted, OnBlankThumbnailHandler blank)
        {
            int doing = ++mDoing;

            Error = null;

            // Debug.WriteLine("Logical-DPI = {0}", DisplayInformation.GetForCurrentView().LogicalDpi);
            var composer = new MediaComposition();

            composer.Clips.Add(clip);

            try
            {
                var totalRange = clip.OriginalDuration.TotalMilliseconds;
                var span       = totalRange / FrameCount;
                var offset     = span / 2;
                for (int n = 0; n < FrameCount; n++)
                {
                    using (var imageStream = await composer.GetThumbnailAsync(TimeSpan.FromMilliseconds(offset + span * n), 0, ThumbnailHeight, VideoFramePrecision.NearestFrame))
                    {
                        if (doing != mDoing)
                        {
                            // cancelling
                            return(false);
                        }
                        var bmp = new BitmapImage();
                        bmp.SetSource(imageStream);     // bmp.SetSourceしたら、imageStreamはすぐDisposeしても大丈夫っぽい。

                        if (null != blank && n == 0)
                        {
                            var source = await CreateBlankBitmap(bmp.PixelWidth, bmp.PixelHeight);

#if false
                            var bb     = new SoftwareBitmap(BitmapPixelFormat.Bgra8, bmp.PixelWidth, bmp.PixelHeight, BitmapAlphaMode.Ignore);
                            var source = new SoftwareBitmapSource();
                            await source.SetBitmapAsync(bb);
#endif
                            blank(this, source);
                        }

                        extracted(this, n, bmp);
                    }
                }
                return(true);
            }
            catch (Exception e)
            {
                CmLog.error("WvvFrameExtractor2.ExtractAsync", e);
                Error = e;
                return(false);
            }
            finally
            {
                composer.Clips.Clear();
            }
        }
예제 #5
0
        /**
         * ソースをMediaPlayerにロードする(非同期版)
         */
        public Task <bool> LoadAsync(MediaSource source, DependencyObject ownerView)
        {
            CmLog.debug("WvvMediaLoader.LoadAsync: async operation started...");

            var task = new TaskCompletionSource <bool>();

            Load(source, ownerView, (loader) =>
            {
                CmLog.debug("WvvMediaLoader.LoadAsync: ... async operation finished.");
                task.TrySetResult(Opened);
            });
            return(task.Task);
        }
예제 #6
0
        /**
         * プレビューモードを開始する。
         *
         * トリミングモード:
         *  MediaPlayerのソースに、オリジナルのソース(StorageFileから生成したもの)をセットした状態。
         *  トリミング操作は、常にこのモードで行い、再生は行わない。
         * プレビューモード:
         *  MediaPlayerのソースに、MediaComposition から生成したストリームを指定し、トリミング後の動画を再生テストするモード
         *  トリミング操作を行うと、自動的にこのモードはキャンセルされ、全体表示モードに戻る。
         */
        private async Task startPreview(bool play)
        {
            if (mPreviewing)
            {
                if (!IsPlaying)
                {
                    mPlayer.Play();
                }
                return;
            }
            if (mTrimmingSlider.TrimmedRange < 100 || mComposition.Clips.Count != 1)
            {
                return;
            }
            mComposition.Clips[0].TrimTimeFromStart = TimeSpan.FromMilliseconds(mTrimmingSlider.TrimStart);
            mComposition.Clips[0].TrimTimeFromEnd   = TimeSpan.FromMilliseconds(mTrimmingSlider.TrimEnd);

            try
            {
                mPreviewing = true;
                MediaStreamSource mediaStreamSource = mComposition.GeneratePreviewMediaStreamSource(
                    (int)mPlayerElement.ActualWidth,
                    (int)mPlayerElement.ActualHeight);

                var loader = await WvvMediaLoader.LoadAsync(mPlayer, MediaSource.CreateFromMediaStreamSource(mediaStreamSource), this);

                if (null != loader)
                {
                    if (mPreviewing)
                    {
                        mPlayer.PlaybackSession.Position = TimeSpan.FromMilliseconds(mTrimmingSlider.CurrentPosition);
                        if (play)
                        {
                            mPlayer.Play();
                        }
                    }
                }
                else
                {
                    mPreviewing = false;
                }
            }
            catch (Exception e)
            {
                CmLog.error(e, "WvvTrimmingView.startPreview: Error");
                mPlayer.Pause();
                mPreviewing = false;
                Error.SetError(e);
            }
        }
예제 #7
0
 public async Task <ImageStream> GetResultImageStream(int height)
 {
     try
     {
         var extractor = new WvvFrameExtractor2(height, 1);
         return(await extractor.ExtractSingleFrameStreamAsync(mClip, TimeSpan.FromMilliseconds(mTrimmingSlider.CurrentPosition)));
     }
     catch (Exception e)
     {
         Error.SetError(e);
         CmLog.error("WvvFrameSelectorView.GetResultImageStream", e);
         return(null);
     }
 }
예제 #8
0
        public async Task <ImageStream> ExtractSingleFrameStreamAsync(StorageFile source, TimeSpan position)
        {
            try
            {
                var clip = await MediaClip.CreateFromFileAsync(source);

                return(await ExtractSingleFrameStreamAsync(clip, position));
            }
            catch (Exception e)
            {
                CmLog.error("WvvFrameExtractor2.ExtractSingleFrameStreamAsync(StorageFile)", e);
                return(null);
            }
        }
예제 #9
0
        /**
         * トラッキング終了時のハンドラ
         */
        private void OnKnobReleased(object sender, PointerRoutedEventArgs e)
        {
            ((UIElement)sender).ReleasePointerCapture(e.Pointer);

            mTracking.Active = false;

            if (null != mTracking.Moved)
            {
                var v = getNewValue(e);
                mTracking.Moved(v, true);
                mTracking.Moved = null;
            }
            CmLog.debug("WvvTrimmingSlider.OnKnobReleased");
            e.Handled = true;
        }
예제 #10
0
 /**
  * ファイルのタイムスタンプを現在時間に更新する
  * - BasicProperty.DateModified
  * - BasicProperty.ItemDate
  * - Properties[System.DateModified]
  * が変更される。
  * 以下のプロパティは変化しない。
  * - StorageFile.DataCreated
  * - Properties[System.DateCreated]
  * - Properties[System.DateAccessed]
  */
 public static async Task TouchFileAsync(StorageFile file)
 {
     // タイムスタンプを更新するための秘技
     // - file.Properties.SavePropertiesAsync()で、ModifiedDate や AccessedDateが変えられない。(ArgumentExceptionがスローされる)
     // - file.OpenAsync(ReadWrite)/Dispose しても、ModifiedDateもAccessedDateも変わらない。
     // - OpenAsyncした後、1バイト読み込んで1バイト書き込む、のような操作をすることも考えたが、気落ち悪い。
     // で、この技・・・0行の文字列を追加する。
     try
     {
         await FileIO.AppendLinesAsync(file, new string[0]);
     }
     catch (Exception e)
     {
         CmLog.error(e, "WvvCacheManager.TouchFileAsync: Error");
     }
 }
예제 #11
0
 /**
  * MediaPlayerでエラーが発生したときの処理
  */
 private async void MP_Failed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
 {
     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
     {
         CmLog.debug("WvvTrimmingView.MP_Failed: MediaFailed");
         if (null != args.ErrorMessage && args.ErrorMessage.Length > 0)
         {
             CmLog.debug(args.ErrorMessage);
             Error.SetError(args.ErrorMessage);
         }
         if (null != args.ExtendedErrorCode)
         {
             CmLog.error(args.ExtendedErrorCode.Message);
             Error.SetError(args.ExtendedErrorCode);
         }
     });
 }
예제 #12
0
        /**
         * MediaFailedイベントのハンドラ
         *
         * --> Errorプロパティのコメント参照
         */
        private async void OnFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
        {
            CmLog.debug("WvvMediaLoader.OnFailed: MediaFailed");
            if (null != args.ErrorMessage && args.ErrorMessage.Length > 0)
            {
                CmLog.debug(args.ErrorMessage);
                Error.SetError(args.ErrorMessage);
            }
            if (null != args.ExtendedErrorCode)
            {
                CmLog.error(args.ExtendedErrorCode.Message);
                Error.SetError(args.ExtendedErrorCode);
            }

            Opened = false;
            await terminate(sender);
        }
예제 #13
0
 /**
  * キャッシュをフォルダ毎削除して再作成
  * Swipe用
  */
 public async Task ClearAllAsync()
 {
     try
     {
         var folder = mFolder.Folder;
         mFolder = null;
         await folder.DeleteAsync();
     }
     catch (Exception e)
     {
         CmLog.error(e, "WvvCacheManager.ClearAllAsync");
     }
     finally
     {
         await InitAsync();
     }
 }
예제 #14
0
        /**
         * URLのキャッシュ(IWvvCache)を取得
         */
        public async Task <IWvvCache> GetCacheAsync(Uri uri)
        {
            WvvCache cache;

            using (mManagerLock.Lock())
            {
                string key = keyFromUri(uri);
                if (!mCacheList.TryGetValue(key, out cache))
                {
                    try
                    {
                        var file = await mFolder.Folder.GetFileAsync(key);
                        await TouchFileAsync(file);

                        cache           = new WvvCache(key, uri, file);
                        mCacheList[key] = cache;
                        CmLog.debug("WvvCacheManager.GetCacheAsync: Use cold cache: {0}", uri.ToString());
                    }
                    catch (FileNotFoundException)
                    {
                        // target is not found in cache
                        cache           = new WvvCache(key, uri, null);
                        mCacheList[key] = cache;
                        CmLog.debug("WvvCacheManager.GetCacheAsync: Use new cache: {0}", uri.ToString());
                    }
                    catch (Exception e2)
                    {
                        CmLog.error(e2, "WvvCacheManager.GetCacheAsync");
                        return(null);
                    }
                }
                else
                {
                    CmLog.debug("WvvCacheManager.GetCacheAsync: Use hot cache: {0}", uri.ToString());
                    var file = cache.CacheFile;
                    if (null != file && cache.RefCount == 0)
                    {
                        await TouchFileAsync(file);
                    }
                }
            }
            cache.AddRef();

            Sweep();
            return(cache);
        }
예제 #15
0
 /**
  * ダウンロードが失敗したときの処理
  */
 private void onDownloadError(Exception error)
 {
     Error = error;
     lock (mLock)
     {
         mFile = null;
         try
         {
             Downloaded?.Invoke(this, null);
             Downloaded = null;
         }
         catch (Exception e)
         {
             // コールバック中のエラーは無視する
             CmLog.error(e, "WvvCache.onDownloadError (error occurred in downloaded-callback(s)... ignored.)");
         }
     }
 }
예제 #16
0
        //private void OnUnloaded(object sender, RoutedEventArgs e)
        //{
        //    Debug.WriteLine("MediaPage Unloaded.");
        //    Dispose();
        //}

        /**
         * リソース解放
         */
        private void Dispose()
        {
            var player = mPlayer.MediaPlayer;

            if (null != player)
            {
                mPlayer.UnregisterPropertyChangedCallback(MediaPlayerElement.IsFullWindowProperty, mFullWindowListenerToken);
                mPlayer.SetMediaPlayer(null);
                player.Dispose();
                //この方法は、Restricted Capabilities の指定が必要なので、できれば避けたい。
                //SystemNavigationManagerPreview.GetForCurrentView().CloseRequested -= OnCloseRequested;
            }
            Closed = null;
            mInfo  = null;


            CmLog.debug("WvvPinPPage.Dispose: PinP Player Disposed.)");
        }
예제 #17
0
        /**
         * 終了処理 (成功時/エラー発生時の共通処理)
         */
        private async Task terminate(MediaPlayer mediaPlayer)
        {
            CmLog.debug("WvvMediaLoader.terminate: (Loading={0})", Loading);

            await OwnerView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                CmLog.debug("WvvMediaLoader.terminate (inner): Loading={0}, hasCallback={0}", Loading, Loaded != null);
                if (Loading)
                {
                    Loading = false;
                    mediaPlayer.MediaOpened -= OnOpened;
                    mediaPlayer.MediaFailed -= OnFailed;
                    if (Opened)
                    {
                        try
                        {
                            TotalRange = Player.PlaybackSession.NaturalDuration.TotalMilliseconds;
                            VideoSize  = new Size(Player.PlaybackSession.NaturalVideoWidth, Player.PlaybackSession.NaturalVideoHeight);
                            CmLog.debug("WvvMediaLoader.terminate (inner): Loaded");
                        }
                        catch (Exception e)
                        {
                            // MediaOpenedが返ってきても、その後、プロパティを参照しようとすると Shutdown済み、みたいな例外が出ることがあって、
                            // このような場合は、ステータスも Closedになっているので、オープン失敗として扱う。
                            CmLog.error(e, "WvvMediaLoader.terminate (inner): Error");
                            Opened             = false;
                            mediaPlayer.Source = null;
                            Error.SetError(e);
                        }
                    }
                    else
                    {
                        mediaPlayer.Source = null;
                        if (!Error.HasError)
                        {
                            Error.SetError("MediaLoader error");
                        }
                    }
                    Loaded?.Invoke(this);
                    Loaded    = null;
                    OwnerView = null;
                }
            });
        }
예제 #18
0
        /**
         * CurrentPosition調整用Thumbがクリックされた
         */
        private void OnThumbPressed(object sender, PointerRoutedEventArgs e)
        {
            ((UIElement)sender).CapturePointer(e.Pointer);

            beginTracking(e, 1, MWidth, AbsoluteCurrentPosition, TotalRange - TrimEnd - TrimStart);

            mTracking.Moved = (v, last) =>
            {
                CurrentPosition = v;
                if (mTracking.Ext != AbsoluteCurrentPosition)
                {
                    mTracking.Ext = AbsoluteCurrentPosition;
                    CurrentPositionChanged?.Invoke(this, CurrentPosition, false);
                }
            };

            CmLog.debug("WvvTrimmingSlider.OnThumbPressed");
            e.Handled = true;
        }
예제 #19
0
        /**
         * TrimEnd位置調整用Knobがクリックされた
         */
        private void OnRKnobPressed(object sender, PointerRoutedEventArgs e)
        {
            ((UIElement)sender).CapturePointer(e.Pointer);

            beginTracking(e, -1, RWidth, TrimEnd, TotalRange - TrimStart - MinimumRange);

            mTracking.Moved = (v, last) =>
            {
                TrimEnd = v;
                if (mTracking.Ext != v)
                {
                    mTracking.Ext = v;
                    TrimEndChanged?.Invoke(this, v, last);
                }
            };

            CmLog.debug("WvvTrimmingSlider.OnRKnobPressed");
            e.Handled = true;
        }
예제 #20
0
 /**
  * ダウンロードが成功したときの処理
  */
 private void onDownloadCompleted(StorageFile file)
 {
     Error = null;
     lock (mLock)
     {
         mFile        = file;
         mInvalidFile = null;
         try
         {
             Downloaded?.Invoke(this, file);
             Downloaded = null;
         }
         catch (Exception e)
         {
             // コールバック中のエラーは無視する
             CmLog.error(e, "WvvCache.onDownloadCompleted (error occurred in downloaded-callback(s)... ignored.)");
         }
     }
 }
예제 #21
0
 /**
  * キャッシュを解放する(CacheManagerによって削除可能な状態にする)
  */
 public void Release()
 {
     lock (mLock)
     {
         mRefCount--;
         if (mRefCount == 0 && mFile == null && mDownloadTask == null && mInvalidFile != null)
         {
             try
             {
                 var _ = mInvalidFile.DeleteAsync();
                 mInvalidFile = null;
             }
             catch (Exception e)
             {
                 CmLog.error(e, "WvvCache.Release (deleting file).");
             }
         }
     }
 }
예제 #22
0
 /**
  * キャッシュファイルを取得する。
  * @param callback  結果を返すコールバック
  */
 public void GetFile(WvvDownloadedHandler callback)
 {
     lock (mLock)
     {
         if (null == mFile)
         {
             if (null == mDownloadTask)
             {
                 Download();
             }
             CmLog.debug("WvvCache.GetFile: Downloading ...");
             Downloaded += callback;
             return;
         }
     }
     // ファイルはキャッシュされている
     CmLog.debug("WvvCache.GetFile: Cache File Available");
     callback(this, mFile);
 }
예제 #23
0
        private async void PBS_StateChanged(MediaPlaybackSession session, object args)
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                CmLog.debug("WvvTrimmingView:PlaybackState = {0}", session.PlaybackState.ToString());
                switch (session.PlaybackState)
                {
                case MediaPlaybackState.None:
                case MediaPlaybackState.Buffering:
                case MediaPlaybackState.Opening:
                case MediaPlaybackState.Paused:
                default:
                    IsPlaying = false;
                    break;

                case MediaPlaybackState.Playing:
                    IsPlaying = true;
                    break;
                }
            });
        }
예제 #24
0
        public async Task <ImageStream> ExtractSingleFrameStreamAsync(MediaClip clip, TimeSpan position)
        {
            Error = null;

            var composer = new MediaComposition();

            composer.Clips.Add(clip);

            try
            {
                return(await composer.GetThumbnailAsync(position, 0, ThumbnailHeight, VideoFramePrecision.NearestFrame));
            }
            catch (Exception e)
            {
                CmLog.error("WvvFrameExtractor2.ExtractSingleFrameStreamAsync(MediaClip)", e);
                Error = e;
                return(null);
            }
            finally
            {
                composer.Clips.Clear();
            }
        }
예제 #25
0
 /**
  * SubWindowの×ボタンがクリックされたときに呼び出される。
  */
 private void OnConsolidated(ApplicationView sender, ApplicationViewConsolidatedEventArgs args)
 {
     CmLog.debug("WvvPinPPage.OnConsolidated: PinP Player Closed.)");
     ApplicationView.GetForCurrentView().Consolidated -= OnConsolidated;
     Close();
 }
예제 #26
0
        /**
         * キャッシュファイル数が制限を超えていたら、古いファイルから削除する
         */
        private async void Sweep()
        {
            // 再入防止
            if (mSweeping)
            {
                return;
            }
            mSweeping = true;
            try
            {
                // キャッシュファイル列挙
                var folder = mFolder.Folder;
                var list   = await folder.GetFilesAsync();

                if (list.Count < MAX_CACHE_COUNT)
                {
                    return;
                }

                // 更新日時(BasicProperty.ItemData)順(昇順)にソート
                var files = new List <TimedFile>(list.Count);
                foreach (var f in list)
                {
                    var bp = await f.GetBasicPropertiesAsync();

                    files.Add(new TimedFile(f, bp.ItemDate));
                }
                files.Sort((x, y) =>
                {
                    return((x.Date < y.Date) ? 1 : (x.Date > y.Date) ? -1 : 0);
                });

                //foreach(var f in files)
                //{
                //    await DumpFileTimeStamp(f.File);
                //}

                // 古いファイルから削除
                for (int i = MAX_CACHE_COUNT; i < files.Count; i++)
                {
                    using (mManagerLock.Lock())
                    {
                        WvvCache cache;
                        if (mCacheList.TryGetValue(files[i].File.Name, out cache))
                        {
                            if (cache.RefCount > 0)
                            {
                                continue;   // 使っているので削除不可 (breakでもよいと思うけど)
                            }
                            mCacheList.Remove(files[i].File.Name);
                        }
                        await files[i].File.DeleteAsync();
                    }
                }
            }
            catch (Exception e)
            {
                CmLog.error(e, "WvvCacheManager.Sweep");
            }
            finally
            {
                mSweeping = false;
            }
        }