4

我曾经用stitchedStreamPlayer 播放流视频。但是,我无法在视频的最后一帧停止。它显示黑屏。我设置属性

[player setActionAtItemEnd:AVPlayerActionAtItemEndPause];

仍然没有在最后一帧停止视频。我应该如何在最后一帧停止?

4

2 回答 2

2

我在这上面花了很多时间,我确认我的视频轨道比音频轨道长,但它仍然不会在最后一帧停止。不过,我想出了一个可怕的技巧来完成这项工作:

// Store as an instance variable so your observation sticks around
private var timeObservation: Any?

override func viewDidLoad() {
    super.viewDidLoad()

    timeObservation = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in
        self?.updateTime(time)
    }
}

private func updateTime(_ time: CMTime) {
    guard let item = player.currentItem else {
        return
    }

    // Assuming the video is 30fps and subtracting two frames. One wasn't enough for me.
    let offset = CMTime(seconds: 2 / 30, preferredTimescale: CMTimeScale(NSEC_PER_SEC))

    // If it's about to play past the end minus our offset, just stop
    if time >= item.duration - offset {
        player.pause()
        player.seek(to: item.duration - offset)
        return
    }
}
我尝试过的其他事情

在我开始使用 HLS 之前,我仍然无法让它在最后一帧暂停,而是AVAssetImageGenerator用来获取最后一帧并将其显示在图像视图中。这看起来有点跳动,压缩/颜色看起来从播放视频到缩略图不同。

我还看到了一些方法,您可以将输出添加到播放器,然后使用它来制作图像。我考虑在最后尝试这样做,但我认为当你检测到需要图像时停止会容易得多。

希望这会有所帮助!

于 2020-11-24T18:51:14.733 回答
0

看来这个问题是由较长的音轨引起的。下面的脚本修复了最后一个 .ts 文件。

last_ts=$(ls -1 "$dir"/out_*.ts | sort | tail -1)
bak=$last_ts.bak
filename="${last_ts##*/}"
basename="${filename%.*}"
workdir=/tmp

# copy only on the first run
[ -f "$bak" ] || cp -r "$last_ts" "$bak"

ffmpeg -y -i "$bak" -vn -c:a copy "$workdir/${basename}_a.ts"

video_stream_info="$(ffprobe "$bak" 2>&1 | grep 'Stream #0:0')"
resolution=$(echo "$video_stream_info" | perl -pe 's/^.*?, ([0-9]*x[0-9]*).*$/\1/g')
fps=$(echo "$video_stream_info" | perl -pe 's/^.*?([0-9.]*) fps.*$/\1/g')
bitrate=""
# FIXME
if [ $quality = low ];then
    bitrate=400k
elif [ $quality = mid ];then
    bitrate=900k
elif [ $quality = high ];then
    bitrate=1200k
fi
extended_duration=$(ffprobe "$bak" 2>&1 | perl -ne '/Duration: (\d*):(\d*):(\d*)\.(\d*)/ && print((((((int($1) * 60) + int($2)) * 60) + int($3)) * 100 + int($4) + 10)/100)')

ffmpeg -y -f lavfi -i nullsrc=s=${resolution}:d=${extended_duration}:r=${fps} -i "$bak" \
       -filter_complex "[0:v][1:v]overlay[video]" -map "[video]" \
       -b:v $bitrate -c:v libx264 -an "$workdir/${basename}_v.ts"

ffmpeg -y -i "$workdir/${basename}_v.ts" -i "$workdir/${basename}_a.ts" \
       -c:a copy -c:v copy \
       "$last_ts"
于 2017-08-04T05:56:50.117 回答