Найдите фактический первый кадр видео, временные метки которого не начинаются с нуля (AVPlayer/AVAsset).IOS

Программируем под IOS
Ответить
Anonymous
 Найдите фактический первый кадр видео, временные метки которого не начинаются с нуля (AVPlayer/AVAsset).

Сообщение Anonymous »

Я работаю над приложением для iOS, которое загружает видео с помощью AVPlayer, и столкнулся с распространенной проблемой: временные метки некоторых видео не начинаются с нуля, поэтому, когда я стремлюсь к нулю, я получаю черную или прозрачную рамку в зависимости от фона проигрывателя.
Например, вы можете воспроизвести это, взяв любой обычный файл MP4 и сдвинув его временные метки с помощью FFmpeg:

Код: Выделить всё

ffmpeg -itsoffset 0.066 -i input.mp4 -c copy output_shifted.mp4
Теперь первый кадр имеет временную метку около 0,066 с.
На самом деле это очень часто случается с видео, записанными камерой или повторно мультиплексированными — они часто не начинаются с нуля из-за смещений кодера или мультиплексора.
Проблема:
Когда я загружаю такой файл в AVPlayer, я не могу искать до реального первого кадра.
Все, что я пытаюсь сделать, сообщает о 0 как о времени начала, хотя FFprobe четко показывает первый PTS около 0,06.
Вот код, который я использую для загрузки и отображения первого кадра перед воспроизведением:

Код: Выделить всё

import SwiftUI
import AVFoundation
import Observation
import AVKit

@MainActor
@Observable
final class VideoPlayerViewModel {
let player = AVPlayer()
private var readyObservation: NSKeyValueObservation?

func prepareAndPlay(url: URL) async throws {
print("preparing")
player.pause()
player.automaticallyWaitsToMinimizeStalling = true

let item = AVPlayerItem(url: url)
player.replaceCurrentItem(with: item)

await readyToPlay(item)
print("ready to play first frame")

// Trying to show the very first frame
await player.seek(to: .zero)
// await player.seek(to: CMTime(value: 3, timescale: 30)) // works if I seek later

try await Task.sleep(for: .seconds(20)) // for demo purposes

print("playing")
player.play()
}

private func readyToPlay(_ item: AVPlayerItem) async {
if item.status == .readyToPlay { return }

await withCheckedContinuation { (cont: CheckedContinuation) in
readyObservation = item.observe(\.status, options: [.initial, .new]) { _, _ in
Task { @MainActor in
switch item.status {
case .readyToPlay, .failed:
self.readyObservation?.invalidate()
cont.resume()
default:
break
}
}
}
}
}
}

struct CustomVideoPlayer: View {
let url: URL
@State private var viewModel = VideoPlayerViewModel()

var body: some View {
VideoPlayer(player: viewModel.player)
.task {
do {
try await viewModel.prepareAndPlay(url: url)
} catch {}
}
}
}

#Preview {
CustomVideoPlayer(
// You can download this video and use the following ffmpeg command to shift the timestamps:
// "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
// ffmpeg -itsoffset 0.066 -i BigBuckBunny.mp4 -c copy video.mp4
// Then copy and paste the video in your project
url: Bundle.main.url(forResource: "video", withExtension: "mp4")!
)
.frame(height: 220)
.background(Color.black)
}
Что я пробовал:
Все следующие API сообщают 0 в качестве времени начала, даже для смещенных видео:
  • Код: Выделить всё

    item.seekableTimeRanges.first
    [*]AVAssetImageGenerator.requestedTimeToleranceBefore/After
    [*]CMSampleBufferGetPresentationTimeStamp
    [*]player.seek(to: .zero)
Что бы я ни делал, я не могу получить или найти эту истинную первую временную метку (например, 0,066 с).
Вопрос:
Есть ли в AVFoundation надежный способ:
  • Получить истинную начальную PTS (метку времени презентации) видеодорожки и
  • Искать фактический первый кадр, даже если временные метки файла не начинаются с нуля?
Также будем признательны за любую информацию о том, как AVFoundation нормализует или смещает это время внутри себя.

Подробнее здесь: https://stackoverflow.com/questions/797 ... rt-at-zero
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»