質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

4231閲覧

Swift AVAssetWriterでの動画生成時のFPSについて

yhl

総合スコア6

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2018/01/23 15:24

###環境
Xcode9.2
Swift4

###概要
現在、画像に対してリアルタイムにエフェクトをかけたものを、動画として書き出そうとしています。
イメージとしてはこのサイトに記載の「画像の配列から動画を生成」と同様に
AVFoundationのAVAssetWriterを使用した方法の中で
AVAssetWriterInputPixelBufferAdaptorに画像のバッファを書き込んでいくものとなります。

しかし、上記のサイトが「決められた数の画像をforループで書き込む」のに対し、私の場合は、マイク音声も別スレッドで録音し最終的に音声と動画を統合したいため
時間軸に沿った、動画書き込みを試みております。

そこでTimer.scheduledTimerでタイマーを回し、毎回以下のように日付から経過時間を取得/AVAssetWriterInputPixelBufferAdaptorに渡すためのCMTimeを出しております。

let FPS = 30 @objec func runLoop(){ let now = Date() let duration = now.timeIntervalSince(offsetDate) offsetDate = now; let presentTime = CMTimeMake(Int64(Float64(frameCount * FPS) * duration), Int32(FPS)) //バッファ追加 flg = adapter.append(baseImageBuffer, withPresentationTime: presentTime)  if !flg { print("error") Thread.sleep(forTimeInterval: 0.1) } }
timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(self.runLoop), userInfo: nil, repeats: true) RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)

###質問
上記の実装にて、タイマーの時間を0.2よりも小さくすると「adapter.append」の箇所で返るBoolがfalseとなり
appendに失敗します。(0.2では動作します)
FTPを30にしたいため、タイマーは1/30=0.03を設定したいのですが、
AVAssetWriterInputPixelBufferAdaptorに書き込む速度制限のようなものが存在するのかどうか
ご存知の方がおりましたらご教示いただけますと幸いです。

ちなみに音声の録音は上記タイマーとは別にAVAudioEngineを走らせ、以下のように実装しておりますが
こちらは正しくオーディオファイルが書き出されます。

mixer = AVAudioMixerNode() audioEngine.attach(mixer) try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord) try! AVAudioSession.sharedInstance().setActive(true) audioFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: 44100.0, channels: 1, interleaved: true) audioEngine.connect(audioEngine.inputNode, to: mixer, format: audioFormat) audioEngine.connect(mixer, to: audioEngine.mainMixerNode, format: audioFormat) let dir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String self.filePath = dir.appending("/temp.wav") _ = ExtAudioFileCreateWithURL(URL(fileURLWithPath: self.filePath!) as CFURL, kAudioFileWAVEType, (audioFormat?.streamDescription)!, nil, AudioFileFlags.eraseFile.rawValue, &outref) mixer.installTap(onBus: 0, bufferSize: AVAudioFrameCount((audioFormat?.sampleRate)!), format: audioFormat) { (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in let audioBuffer: AVAudioBuffer = buffer _ = ExtAudioFileWriteAsync(self.outref!, buffer.frameLength, audioBuffer.audioBufferList) }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

原因は経過時間の算出で余計なことをしていたようです。

Timer.scheduledTimerでFPSを再現しているので
AVAssetWriterInputPixelBufferAdaptorに渡すwithPresentationTimeは
単に経過時間を足していって
それを渡せばよかったようです。

swift

1let duration = now.timeIntervalSince(offsetDate) 2totalTime += duration 3 4let presentTime = CMTimeMakeWithSeconds(totalTime, Int32(NSEC_PER_SEC))

ありがとうございました。

投稿2018/01/25 06:10

yhl

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問