HTML5视频:如何获取当前帧的索引

huangapple go评论61阅读模式
英文:

HTML5 Video: How to get the index of current frame

问题

我有一个Web应用程序,使用这个 WebCodecs库逐帧处理mp4视频,并存储每个VideoFrame的呈现时间戳和持续时间。

然后,我想播放视频并将当前播放的帧与处理过的帧进行匹配。为此,我使用requestVideoFrameCallback。由于视频可能具有可变的帧速率,我不能仅仅使用currentTime / FPS或甚至VideoFrameCallbackMetadata.mediaTime / FPS。相反,我尝试找到具有Timestamp <= VideoFrameCallbackMetadata.mediaTime && Timestamp + Duration >= VideoFrameCallbackMetadata.mediaTime的VideoFrame。但即使这样做也不一致,因为在某些视频上,第一帧的timestamp > 0,但HTML5视频在视频开始时显示这一帧,当currentTime = 0,甚至mediaTime = 0

是否有一种方法可以将VideoFrames与HTML视频元素中显示的帧进行匹配?我认为mediaTime应该与VideoFrame时间戳一致,但事实并非如此。

编辑:我注意到第一个处理过的帧有时候timestamp > 0,但运行FFProbe显示,第一帧应该有timestamp==0。而且处理的帧数有时低于info.VideoTracks.nb_samples。所以我认为这可能是库中的错误。

编辑2:导致未处理所有帧的库错误现已修复。但是,第一帧的时间戳仍与使用FFProbe提取的时间戳不同ffprobe file.mp4 -select_streams v -show_entries frame=coded_picture_number,pkt_pts_time -of csv=p=0:nk=1 -v 0。我将尝试将FFProbe输出与MP4Box命令行进行比较,看看时间戳差异出现在何处。另一个可能的原因是视频元素本身以不同的时间戳渲染帧。

编辑3:即使使用来自FFProbe的帧时间戳,帧时间仍然与视频元素不同步。

英文:

I have a web application that processes mp4 video frame-by-frame using this WebCodecs library and stores the presentation timestamp and duration of every VideoFrame.

Then i want to play the video and match the currently playing frame with the processed frames. For this i use the requestVideoFrameCallback. Since the video can have variable framerate, I cannot just use currentTime / FPS or even VideoFrameCallbackMetadata.mediaTime / FPS. Instead I try to find the VideoFrame that has Timestamp &lt;= VideoFrameCallbackMetadata.mediaTime &amp;&amp; Timestamp + Duration &gt;= VideoFrameCallbackMetadata.mediaTime. But even this is not consistent because on some videos the first frame has timestamp &gt; 0 but the html5 video displays this frame on the start of the video when currentTime = 0 and even mediaTime = 0.

Is there a way to match the VideoFrames to the frame that is displayed in the html video element? I thought the mediaTime should be consistent with the VideoFrame timestamp but it is not.

EDIT: I noticed that the first processed frame sometimes has timestamp &gt; 0 but running FFProbe shows that the first frame should have timestamp==0. Also The number of frames that are processed is sometimes lower that the info.VideoTracks.nb_samples. So I think this is probably error in the library.

EDIT2: The bug in the library that caused not all frames to be processed is now fixed. However, The timestamp of the first frame still differs from the timestamp extracted using FFProbe ffprobe file.mp4 -select_streams v -show_entries frame=coded_picture_number,pkt_pts_time -of csv=p=0:nk=1 -v 0. I'm going to try to compare FFProbe output to MP4Box command line to see where does the difference in timestamps occur. Another culrpit could be the video element itself rendering the frames with different timestamps.

EDIT3: Even when using the frame timestamps from FFProbe, the frame times are still not in sync with the video element.

答案1

得分: 1

从我的经验来看,requestVideoFrame 不够精确到帧级别。我认为原因是您无法控制视频元素如何操作底层编解码器。为了精确到帧级别工作,我自己操作了编解码器,不过我的目标不同(我构建了一个视频编辑器)。在您的情况下,可以在转向编解码器之前尝试使用 MediaStreamTrackProcessor API https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrackProcessor。在我的情况下,它比 requestVideoFrame 更准确,但仍然不够精确。在您的情况下,它可能会起作用:

const videoTrack = document.querySelector("video").videoTracks[0]; //原始视频
const trackProcessor = new MediaStreamTrackProcessor({ track: videoTrack }); //输入视频轨道
const trackGenerator = new MediaStreamTrackGenerator({ kind: "video" }); //输出视频轨道

const reader = trackProcessor.reader //从输入视频轨道获取流
const transformer = new TransformStream({
  async transform(videoFrame, controller) {
    const newFrame = myFunction(videoFrame, processedFrame) //在这里,您将生成一个新的视频帧,其中包含旧的处理过的帧与原始帧叠加或并排显示。
    videoFrame.close();
    controller.enqueue(newFrame);
  },
});

trackProcessor.readable
  .pipeThrough(transformer)
  .pipeTo(trackGenerator.writable);

之后,您将不得不将输出轨道附加到不同的视频元素上,该元素将播放新的帧。

英文:

From my experience, requestVideoFrame is not precise to the frame level. The reason for that, I believe, is that you don't have control over the way the video element manipulates the underlying codecs. What I did to work precisely to the frame level was to manipulate the codecs myself, however, my goal was different (I built a video Editor). In your case, before going to the codecs themselfs, you can try to use the MediaStreamTrackProcessor API https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrackProcessor. In my case it was more accurate then requestVideoFrame, but still not accurate enough. In your case It might do the trick:

const videoTracks = document.querySelector(&quot;video&quot;).videoTracks[0]; //originl video
const trackProcessor = new MediaStreamTrackProcessor({ track: videoTrack }); //input videoTrack
const trackGenerator = new MediaStreamTrackGenerator({ kind: &quot;video&quot; }); //output videoTrack

const reader = trackProcessor.reader //get stream from input videoTrack
const transformer = new TransformStream({
  async transform(videoFrame, controller) {
    const newFrame = myFunction(videoFrame, processedFrame) //here you&#39;ll generate a new videoFrame with the old processed Frame overlaid or side-by-side with the original frame.
    videoFrame.close();
    controller.enqueue(newFrame);
  },
});

trackProcessor.readable
  .pipeThrough(transformer)
  .pipeTo(trackGenerator.writable);

After that, you'll have to attach the output track to a differente video element, which will play the new frames.

答案2

得分: 0

最后,我通过将所有的帧时间戳向后偏移,以使第一帧从0:00开始(mp4box有时会输出大于0的时间戳,而ffmpeg不会)。这已经很接近了,但有些帧仍然会渲染在前一帧之后1帧。因此,当时间戳非常接近下一帧(大约5微秒)时,我会渲染下一帧。

虽然有些繁琐,但这似乎效果相当不错。

英文:

In the end I solved it by shifting all of the frame timestamps so that the first frame starts at 0:00 (mp4box sometimes outputs timestamp > 0 for the first frame, ffmpeg does not). This was close, but some frames were still rendering 1 frame behind. So when a timestamp is very close to next frame (about 5 microseconds) I render the next frame instead.

Although cumbersome, this seems to work pretty well.

huangapple
  • 本文由 发表于 2023年6月29日 18:42:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76580269.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定