为什么AVPlayer不会在HLS流视频的最后一帧停止?

时间:2013-07-08 13:48:28

标签: ios objective-c video-streaming avplayer

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

[player setActionAtItemEnd:AVPlayerActionAtItemEndPause];

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

2 个答案:

答案 0 :(得分: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来获取最后一帧并将其显示在图像视图中。这看起来有些跳动,压缩/颜色看上去与正在播放的视频到缩略图都不一样。

我还看到了一些方法,可以在其中向播放器添加输出,然后使用该图像制作图像。我考虑过只在最后尝试这样做,但是我认为只要发现需要图像就停下来就容易多了。

希望这会有所帮助!

答案 1 :(得分: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"