web-dev-qa-db-ja.com

AVPlayerItemがAVStatusFailedおよびエラーコード「Cannot Decode」で失敗する

奇妙な問題に遭遇しています。誰か助けてくれるといいのですが。

私のiOSアプリでは、ユーザーの写真ライブラリの動画とアプリバンドルの音声ファイルを組み合わせて、MutableCompositionを使用してカスタムサウンドトラック付きの動画を作成します。次に、AVPlayerおよびAVPlayerItemを使用して、作成したカスタムビデオプレーヤーを使用してユーザーにビデオを再生します。

新しいコンポジションが作成されるたびに、アセット、プレーヤー、コンポジションはクリアされてリリースされ、基本的にはクリーンな初期状態から始まります。

この方法で4つの成功した動画が作成された後、プレーヤーを作成しようとする他のすべての試みがエラーCannot Decodeで失敗するまで、すべてが正常に機能します。私が再作成している同じビデオがビデオまたはオーディオファイルのサイズ/長さに関係なくても、時計仕掛けのように5回目の試行で常に失敗するだけでかまいません。失敗すると、常に失敗します。

これは奇妙なことです。問題なく同じビデオを4回デコードしただけなので、突然失敗しますか?ですから、手がかりがあったら教えてください。

32
user1112293

皆さん、わかりました。私はこれに対する答えをAppleから直接受け取っています。私は開発者のTSIライフラインの1つを使用して質問をし、回答を要約します。

AVFoundationで許可される同時ビデオプレーヤーの数には制限があります。これは、iOSハードウェアの制限によるものです。現在のデバイスの制限は4プレーヤーです。 5番目のプレーヤーを作成すると、「デコードできません」エラーが発生します。 AVPlayerまたはAVPlayerItemのインスタンスの数に制限はありません。むしろ、「レンダーパイプライン」を作成するAVPlayerItemとAVPlayerItemの関連付けであり、これらのうち4つに制限されます。たとえば、これにより新しいレンダリングパイプラインが発生します。

AVPlayer *player = [AVPlayer playerWithPlayerItem:somePlayerItem];  
// assuming the AVPlayerItem is ready to go with an AVAsset that has been loaded

また、4つのパイプラインを使用できるとは想定できないことも警告されました。別のアプリが1つ以上使用している可能性があります。実際、これがiPadで発生するのを見たことがありますが、どのアプリがパイプラインを使用しているかは明確ではありませんでした。

だから、あなたが行く、それは完全に文書化されていませんでしたが、それは物語です。

73
one09jason

4つのAVPlayerインスタンスを作成した後、同じエラーメッセージに遭遇しましたが、私の場合の修正はまったく同じではありませんでした。おそらく、これはこの問題に遭遇した他の人を助けるでしょう。

私が最終的に見つけたのは、私が思っていたときにAVプレーヤーがリリースされていなかったことです。私の場合、私はAVPlayer View Controllerをナビゲーションコントローラーにプッシュしていました。一度に作成するAVPlayerインスタンスは1つだけでしたが、ビューコントローラーがナビゲーションコントローラーからポップされると、すぐには解放されませんでした。古いビューコントローラーがクリーンアップされる前に、4つのAVPlayerインスタンスに到達するのは非常に簡単でした。

この問題が解決したのは、以前のプレーヤーがリリースされたことを確認するまででした。完了するには、AVPlayerItem、AVPlayerを解放し、解放する前にAVPlayerLayerのプレーヤーをnilに設定しました。

AVPlayerインスタンスに意図的かどうかにかかわらず、いくつかの制限があるかどうか疑問に思います。ドキュメントからの関連情報: https://developer.Apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html

「複数のプレーヤーレイヤー:1つのAVPlayerインスタンスから任意の数のAVPlayerLayerオブジェクトを作成できますが、最近作成されたそのようなレイヤーだけがビデオコンテンツを画面に表示します。」

7
Andrew Wood

これは、私がそれを理解し、このスレッドと他のいくつかの手がかりを手に入れるまで、絶対にkillingでした。私のコードの最大の単一の問題は、ビデオを再生したいたびにビデオプレーヤーコントローラをインスタンス化していたことです。これで、プライマリコントローラ(この場合は、私のDetailViewContoller)でインスタンス化されます

@interface DetailViewController () {
    VideoPlayerViewController *videoPlayerViewController;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    videoPlayerViewController = [[VideoPlayerViewController alloc] initWithNibName: nil bundle: nil];
}

ビデオを表示したいときは、DetailViewControllerのstartVideoPlaybackメソッドを呼び出します。

- (void) startVideoPlayback: (NSString *)videoUID
{
    videoPlayerViewController.videoUID = videoUID;
    [self presentModalViewController: videoPlayerViewController animated: YES];
}

(注: 'videoUID'を渡しています。これは、アプリの別の部分でビデオを作成するために使用された一意のIDです。)

VideoPlayerViewController(これは主にAppleの AVPlayerDemo サンプルから引用されています)では、1回限りの画面設定(AVPlayerの初期化、ツールバーの設定など)がviewDidLoad-これはonceだけが呼び出されるようになり、すべてのビデオごとの設定はviewWillAppear、次にprepareToPlayを呼び出します:

- (void) prepareToPlay
{
    [self initScrubberTimer];   
    [self syncPlayPauseButtons];
    [self syncScrubber];

    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    //*** Retrieve and play video at associated with this videoUID
    NSString *destinationPath = [documentsDirectory stringByAppendingFormat: @"/%@.mov", videoUID];
    if ([self fileExists: destinationPath]) {

        //*** Show the activity indicator spinny thing
        [pleaseWait startAnimating];
        [self setURL: [NSURL fileURLWithPath: destinationPath]];
        //*** Get things going with the first video in this session
        if (isFirst) {
            isFirst = NO;
        //*** Subseqeunt videos replace the first one
        } else {
            [self.mPlayer replaceCurrentItemWithPlayerItem: [AVPlayerItem playerItemWithURL: [NSURL fileURLWithPath: destinationPath]]];
        }
    }
}
3
mpemburn

わかりました。解決策を見つけました。これがこの問題に似たものに遭遇する可能性のあるすべての人に役立つことを願っています。

私の場合の解決策は、メインスレッドでAVPlayerとAVPlayerItemのアセットを初期化し、playerItemとプレーヤーオブジェクトがステータス「ReadyToPlay」で戻る前に実際のAVPlayerLayerを作成しないようにすることでした。

これは分離するのが難しいことが判明しましたが、最初の4回は正常に機能し、その後5回目には常に失敗する理由がわかりません。

それまでは、コードを実際に含めることはできませんでした。1行でも、数個の関数でもかまいません。それは私が最初に分離することができなかった複雑な問題でした。コメントありがとうございます。

2
user1112293