<p>For MP4/MOV files, you could do this as follows:</p>
<p>Say you wanted the frame number for frame at 1:05.00 (65.00s)</p>
<p>Run</p>
<p><code>ffmpeg -ss 1:05 -copyts -noaccurate_seek -i input.mp4 -vf &quot;select=gte(t\,64.8)*lt(t\,65.20) &quot; -f null -  -v 56 2&gt;&amp;1 | grep -e &quot;timestamp&quot; -e &quot;select_out:0&quot;</code></p>
<p>For Rotem's test file, this produces</p>
<pre><code>[mov,mp4,m4a,3gp,3g2,mj2 @ ...] stream 0, timestamp 663552, sample 500
[Parsed_select_0 @ ...] n:148.000000 pts:663552.000000 t:64.800000 key:0 interlace_type:P pict_type:P scene:nan -&gt; select:1.000000 select_out:0
[Parsed_select_0 @ ...] n:149.000000 pts:664576.000000 t:64.900000 key:0 interlace_type:P pict_type:B scene:nan -&gt; select:1.000000 select_out:0
[Parsed_select_0 @ ...] n:150.000000 pts:665600.000000 t:65.000000 key:0 interlace_type:P pict_type:P scene:nan -&gt; select:1.000000 select_out:0
[Parsed_select_0 @ ...] n:151.000000 pts:666624.000000 t:65.100000 key:0 interlace_type:P pict_type:B scene:nan -&gt; select:1.000000 select_out:0
</code></pre>
<p>So the nearest prior keyframe is #500, and the desired frame is #150 starting from the keyframe, hence an absolute index of 650, starting from 0, thus the 651st frame.</p>
<p>This process keeps the decoding to a minimum. You can alter the radius in the select expression based on the framerate.</p>
<hr />
<p>Edit: the original method will be restored in ffmpeg 7.1<br />
Edit2: My earlier answer didn't account for frame reordering. Modified process.</p>

CC BY-SA 4.0
2024-09-13T19:07:03.067Z
2024-09-14T11:00:21.843Z
2024-09-14T11:00:21.843Z
Gyan
<p>We may use FFprobe <a href="https://stackoverflow.com/a/28376817/4926757">frames counting</a>:</p>
<p><code>ffprobe -read_intervals &quot;%+01:05.01&quot; -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4</code></p>
<hr />
<p><code>-read_intervals &quot;%+01:05.01 ...&quot;</code> - stops counting when timestamp reaches 01:05 (add 0.01 for including timestamp 01:05).</p>
<hr />
<p>Example:</p>
<p>Build input video file <code>input.mp4</code> for testing (1000 frames at 10fps):<br />
<code>ffmpeg -y -f lavfi -r 10 -i testsrc=size=384x216:rate=1:duration=1000 -vf setpts=N/TB/10 -c:v libx264 input.mp4</code></p>
<p>Executing:</p>
<p><code>ffprobe -read_intervals &quot;%+01:05.01&quot; -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4</code></p>
<p>Output:<br />
<code>651</code></p>
<p>Note: The result starts counting from 1.</p>

CC BY-SA 4.0
2024-09-14T04:29:26.410Z
With a read interval starting at the beginning and the printing of frame properties, this will decode all frames. If the timestamp is, say, 1h30m in a 30 fps stream, that's 162000 frames!
Gyan
CC BY-SA 4.0
2024-09-14T08:12:25.620Z
I know, but the [original method](https://stackoverflow.com/a/69693602/4926757) also traverses all the frames. I assume FFprobe doesn't decode all the frames, just parse all the frames. Your solution is much more efficient, but the output is 647. It is also not going to work when there is no PTS=65.0000 (say it is 65.01) . Please note that I am not trying to compete with your answer. I  had my answer ready after the OP posted the question in Super User, but moved it to Video Production site.
Rotem
CC BY-SA 4.0
2024-09-14T10:28:22.697Z
The original method uses `-vcodec copy` and fffprobe needs to decode frames if `show_frames` or `show_entries frame=` is specified.
Gyan
CC BY-SA 4.0
2024-09-14T11:01:02.707Z
I forgot about frame reordering. Modified answer.
Gyan
CC BY-SA 4.0
2024-09-14T12:33:35.627Z
I updated my answer with `-count_packets`. It's simpler than my previous solution, and probably faster than my previous solution.
Rotem
CC BY-SA 4.0
2024-09-13T20:29:34.920Z
2024-09-14T12:31:33.840Z
2024-09-14T12:31:33.840Z
Rotem
<p>My question is based on the answer given here <a href="https://stackoverflow.com/a/69693602">https://stackoverflow.com/a/69693602</a>.</p>
<p>The question asked was</p>
<blockquote>
<p>How can I get the frame number closest to a given time (relative to the start of the video) using ffmpeg?</p>
</blockquote>
<p>The proposed answer is to use following command and parse the output for <code>frame=</code> value:</p>
<pre><code>ffmpeg -t 01:05 -i input.mp4 -nostats -vcodec copy -y -f rawvideo /dev/null
</code></pre>
<p>Using that command with ffmpeg 6.1.1 or higher omits the output of <code>frame=</code> value:</p>
<pre><code>[out#0/rawvideo @ 0x603658390f80] video:10789kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%
size=   10789kB time=00:00:07.46 bitrate=11837.3kbits/s speed=2.01e+03x
</code></pre>
<p>Does anyone know a solution for that problem with ffmpeg &gt;= 6.1.1?</p>

<ffmpeg><video>
How to get frame number given a timestamp using ffmpeg
Max Chr.
# How to get frame number given a timestamp using ffmpeg

(Asked by: username_0 on 2024-09-13)

My question is based on the answer given here https://stackoverflow.com/a/69693602.
The question asked was

How can I get the frame number closest to a given time (relative to the start of the video) using ffmpeg?

The proposed answer is to use following command and parse the output for frame= value:
ffmpeg -t 01:05 -i input.mp4 -nostats -vcodec copy -y -f rawvideo /dev/null

Using that command with ffmpeg 6.1.1 or higher omits the output of frame= value:
[out#0/rawvideo @ 0x603658390f80] video:10789kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%
size=   10789kB time=00:00:07.46 bitrate=11837.3kbits/s speed=2.01e+03x

Does anyone know a solution for that problem with ffmpeg >= 6.1.1?

**Tags:** ffmpeg, video


---

## 2 answers

### Answer by username_2 on 2024-09-13. Score: 3 | Accepted answer

We may use FFprobe [frames counting](https://stackoverflow.com/a/28376817/4926757):

`ffprobe -read_intervals "%+01:05.01" -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4`

---

`-read_intervals "%+01:05.01 ..."` - stops counting when timestamp reaches 01:05 (add 0.01 for including timestamp 01:05).

---

Example:

Build input video file `input.mp4` for testing (1000 frames at 10fps):  
`ffmpeg -y -f lavfi -r 10 -i testsrc=size=384x216:rate=1:duration=1000 -vf setpts=N/TB/10 -c:v libx264 input.mp4`

Executing:

`ffprobe -read_intervals "%+01:05.01" -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4`

Output:  
`651`

Note: The result starts counting from 1.

> **Comments:**
> **username_1**: With a read interval starting at the beginning and the printing of frame properties, this will decode all frames. If the timestamp is, say, 1h30m in a 30 fps stream, that's 162000 frames!  
> **username_2**: I know, but the [original method](https://stackoverflow.com/a/69693602/4926757) also traverses all the frames. I assume FFprobe doesn't decode all the frames, just parse all the frames. Your solution is much more efficient, but the output is 647. It is also not going to work when there is no PTS=65.0000 (say it is 65.01) . Please note that I am not trying to compete with your answer. I  had my answer ready after the OP posted the question in Super User, but moved it to Video Production site.  
> **username_1**: The original method uses `-vcodec copy` and fffprobe needs to decode frames if `show_frames` or `show_entries frame=` is specified.  
> **username_1**: I forgot about frame reordering. Modified answer.  
> **username_2**: I updated my answer with `-count_packets`. It's simpler than my previous solution, and probably faster than my previous solution.  

---

### Answer by username_1 on 2024-09-13. Score: 2

For MP4/MOV files, you could do this as follows:
Say you wanted the frame number for frame at 1:05.00 (65.00s)
Run
ffmpeg -ss 1:05 -copyts -noaccurate_seek -i input.mp4 -vf "select=gte(t\,64.8)*lt(t\,65.20) " -f null -  -v 56 2>&1 | grep -e "timestamp" -e "select_out:0"
For username_2's test file, this produces
[mov,mp4,m4a,3gp,3g2,mj2 @ ...] stream 0, timestamp 663552, sample 500
[Parsed_select_0 @ ...] n:148.000000 pts:663552.000000 t:64.800000 key:0 interlace_type:P pict_type:P scene:nan -> select:1.000000 select_out:0
[Parsed_select_0 @ ...] n:149.000000 pts:664576.000000 t:64.900000 key:0 interlace_type:P pict_type:B scene:nan -> select:1.000000 select_out:0
[Parsed_select_0 @ ...] n:150.000000 pts:665600.000000 t:65.000000 key:0 interlace_type:P pict_type:P scene:nan -> select:1.000000 select_out:0
[Parsed_select_0 @ ...] n:151.000000 pts:666624.000000 t:65.100000 key:0 interlace_type:P pict_type:B scene:nan -> select:1.000000 select_out:0

So the nearest prior keyframe is #500, and the desired frame is #150 starting from the keyframe, hence an absolute index of 650, starting from 0, thus the 651st frame.
This process keeps the decoding to a minimum. You can alter the radius in the select expression based on the framerate.

Edit: the original method will be restored in ffmpeg 7.1
Edit2: My earlier answer didn't account for frame reordering. Modified process.


---

