iina / iina

The modern video player for macOS.
https://iina.io
GNU General Public License v3.0
37.18k stars 2.53k forks source link

IINA Refuses to Play From the Beginning of the Video Despite Being Told So #4607

Open Sponge-bink opened 10 months ago

Sponge-bink commented 10 months ago

System and IINA version:

Expected behavior:

The exact opposite of Actual behavior

Actual behavior:

When I open a video for the first time or when I seek to absolute 0 with seek 0 absolute or when I drag the progress bar to the left-most position, IINA will not play the video from the beginning, the first frame.

I can tell it didn't started from the beginning because after I seek or I drag the progress bar I can actually perform Previous Frame and see some frames before that frame IINA shows me. I know those are frames before the IINA-decided frame because I recorded the video myself.

Steps to reproduce:

Open the video, and see Actual behavior.

Yes, I can confirm that MPV does not have this problem.

How often does this happen?

For the specific video, always.

low-batt commented 10 months ago

Did not reproduce for me.

Need a small example video that reproduces the problem. If there is trouble attaching it directly to this issue you can upload it to: THE NULL POINTER

Was the video taken with an iPhone? There is one known mpv problem related to seeking in videos taken with an iPhone, but this doesn't sound like that problem.

Binding a key to seek 0 absolute is likely malfunctioning due to IINA issue #3710.

When comparing IINA and mpv behavior keep in mind that by default IINA enables hardware decoding whereas mpv defaults to software decoding. When it comes to playback problems that can be an important factor.

For my testing I enabled Pause under the When media is opened setting found in the General tab of IINA settings. I also bound the arrow keys to frame-step and frame-back-step. In Additional mpv options on the Advanced tab of IINA settings I set input-ipc-server to /mpv/mpv-socket. On IINA's OSC I right clicked the time and selected 1 millisecond for Precision.

Enabling mpv's IPC server allowed me to paste the following commands into Terminal to see where libmpv thinks playback is positioned:

echo '{ "command": ["get_property", "time-pos"] }' | socat - /tmp/mpv-socket
echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpv-socket
echo '{ "command": ["get_property", "percent-pos"] }' | socat - /tmp/mpv-socket
echo '{ "command": ["get_property", "estimated-frame-number"] }' | socat - /tmp/mpv-socket

To be able to do this I used Homebrew to install socat.

These commands check the value of the following mpv properties:

IINA uses time-pos to display the time in the OSC.

To test I checked the position at the start and then used the OSC slider to reposition the video to another time and then back to the start. As can be seen here mpv is indicating it thinks playback is positioned at the first frame:

low-batt@gag ~$ echo '{ "command": ["get_property", "time-pos"] }' | socat - /tmp/mpv-socket
{"data":0.000000,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpv-socket
{"data":0.000000,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "percent-pos"] }' | socat - /tmp/mpv-socket
{"data":0.000000,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "estimated-frame-number"] }' | socat - /tmp/mpv-socket
{"data":0,"request_id":0,"error":"success"}
low-batt@gag ~$ 

After stepping forward one frame:

low-batt@gag ~$ echo '{ "command": ["get_property", "time-pos"] }' | socat - /tmp/mpv-socket
{"data":0.033333,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpv-socket
{"data":0.033333,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "percent-pos"] }' | socat - /tmp/mpv-socket
{"data":0.178329,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "estimated-frame-number"] }' | socat - /tmp/mpv-socket
{"data":1,"request_id":0,"error":"success"}
low-batt@gag ~$ 

With the OSC set to millisecond precision you can see the time change when stepping.

There are lots of different ways to encode videos. The problem at hand may be a defect in handling the particular encoding used by the video that exhibits the problem.

Sponge-bink commented 10 months ago

Was the video taken with an iPhone?

It was a screen-recording by an iPhone. Trimmed on an iPhone (Photos app), AirDropped to Mac, and then trimmed on the Mac several times (space bar previewing in Finder, saved by replacing the original).

Need a small example video that reproduces the problem.

I couldn't upload the original video due to privacy reasons, but I re-done the whole process, and the video I got has the same problem:

https://github.com/iina/iina/assets/33798984/96766877-9079-4758-a1aa-b44200220f7c

It stops at 00:00:007 when I dragged the progress bar to the beginning / seek to absolute 0.

For my testing I enabled Pause under the When media is opened setting found in the General tab of IINA settings. I also bound the arrow keys to frame-step and frame-back-step. In Additional mpv options on the Advanced tab of IINA settings I set input-ipc-server to /mpv/mpv-socket. On IINA's OSC I right clicked the time and selected 1 millisecond for Precision.

I tried this on my machine and the commands didn't fail but gave me nothing at all.

low-batt commented 10 months ago

Thank you very much for taking the time to create the video that demonstrates the problem.

Reproduced for me with both IINA and mpv.

At this point I should mention that I am a newbie junior IINA developer operating outside of my technical expertise. If an expert happens to chime in and indicate my analysis is wrong, you should believe them, not me.

On the IPC interface not working for you… I suggest complaining bitterly to low-batt about the typo in the instructions:

set input-ipc-server to /mpv/mpv-socket

That should be /tmp/mpv-socket to match up with the path passed to socat:

echo '{ "command": ["get_property", "time-pos"] }' | socat - /tmp/mpv-socket

Sorry! Although I would have expected that would result in the following error, not "nothing at all":

low-batt@gag ~$ echo '{ "command": ["get_property", "time-pos"] }' | socat - /tmp/mpv-socket
2023/09/02 17:28:20 socat[81789] E UNIX-CLIENT:/tmp/mpv-socket: Connection refused

Back to the reported problem…

Digital videos files distributed to consumers use various compression techniques to reduce the size of the file. An important compression technique is the use of keyframes. A series of full pictures can be replaced by a full keyframe followed by interframes that only contain changes to make to that keyframe. Imagine a video of a ballpark with a baseball moving through the sky. The keyframe would be a complete picture of the park and baseball. The following interframes would contain instructions to erase the baseball where it was and paint it in its new position. The IBM tutorial Keyframes, InterFrame & Video Compression is a good introduction to video compression.

Given this structure you would expect a digital video file to start with a keyframe with interframes following. The structure of a video file can be seen using ffprobe.

The following ffprobe output shows the encoding of a video file that does not exhibit the problem. Note that the file starts with audio and video keyframes:

FFprobe Output: ```text low-batt@gag issue-4607$ ffprobe -loglevel error -pretty -of compact -show_frames -show_entries frame=media_type,key_frame,pts_time ~/Movies/Big\ Buck\ Bunny\ 60fps\ 4K\ -\ Official\ Blender\ Foundation\ Short\ Film\ \[aqz-KE-bpKQ\].mp4 frame|media_type=video|key_frame=1|pts_time=0:00:00.000000 frame|media_type=audio|key_frame=1|pts_time=0:00:00.000000 frame|media_type=video|key_frame=0|pts_time=0:00:00.016667 frame|media_type=audio|key_frame=1|pts_time=0:00:00.021333 frame|media_type=video|key_frame=0|pts_time=0:00:00.033333 frame|media_type=audio|key_frame=1|pts_time=0:00:00.042667 frame|media_type=video|key_frame=0|pts_time=0:00:00.050000 frame|media_type=audio|key_frame=1|pts_time=0:00:00.064000 frame|media_type=video|key_frame=0|pts_time=0:00:00.066667 frame|media_type=video|key_frame=0|pts_time=0:00:00.083333 frame|media_type=audio|key_frame=1|pts_time=0:00:00.085333 ```

Probing the video file that exhibits the problem, focusing on the video stream shows 16 video interframes before the first keyframe:

FFprobe Output: ```text low-batt@gag issue-4607$ ffprobe -loglevel error -pretty -of compact -select_streams v:0 -show_frames -show_entries frame=media_type,key_frame,pts_time ./265201812-96766877-9079-4758-a1aa-b44200220f7c.mov frame|media_type=video|key_frame=0|pts_time=0:00:00.000000 frame|media_type=video|key_frame=0|pts_time=0:00:00.016667 frame|media_type=video|key_frame=0|pts_time=0:00:00.033333 frame|media_type=video|key_frame=0|pts_time=0:00:00.050000 frame|media_type=video|key_frame=0|pts_time=0:00:00.066667 frame|media_type=video|key_frame=0|pts_time=0:00:00.083333 frame|media_type=video|key_frame=0|pts_time=0:00:00.100000 frame|media_type=video|key_frame=0|pts_time=0:00:00.116667 frame|media_type=video|key_frame=0|pts_time=0:00:00.133333 frame|media_type=video|key_frame=0|pts_time=0:00:00.150000 frame|media_type=video|key_frame=0|pts_time=0:00:00.166667 frame|media_type=video|key_frame=0|pts_time=0:00:00.183333 frame|media_type=video|key_frame=0|pts_time=0:00:00.200000 frame|media_type=video|key_frame=0|pts_time=0:00:00.216667 frame|media_type=video|key_frame=0|pts_time=0:00:00.233333 frame|media_type=video|key_frame=0|pts_time=0:00:00.250000 frame|media_type=video|key_frame=1|pts_time=0:00:00.266667 ```

Assuming my understanding is correct, a player will not be able to render these initial frames as the keyframe they are associated with is missing.

What I would like to know is what the video encoding standards have to say about such encodings and how a conforming player must handle a video encoded like this. For that we'd need a software engineer familiar with the standards.

Running mpv like so:

mpv -autofit=75%x75% -input-ipc-server=/tmp/mpv-socket --pause ./265201812-96766877-9079-4758-a1aa-b44200220f7c.mov

And checking the position shows:

low-batt@gag ~$ echo '{ "command": ["get_property", "time-pos"] }' | socat - /tmp/mpv-socket
{"data":-0.728333,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpv-socket
{"data":-0.728333,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "percent-pos"] }' | socat - /tmp/mpv-socket
{"data":0.000000,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "estimated-frame-number"] }' | socat - /tmp/mpv-socket
{"data":0,"request_id":0,"error":"success"}
low-batt@gag ~$ 

Instructing mpv to seek to 0:

low-batt@gag ~$ echo '{ "command": ["seek", "0", "exact"] }' | socat - /tmp/mpv-socket
{"data":null,"request_id":0,"error":"success"}
low-batt@gag ~$ echo '{ "command": ["get_property", "time-pos"] }' | socat - /tmp/mpv-socket
{"data":-0.728333,"request_id":0,"error":"success"}
low-batt@gag ~$ 

I'm not understanding how mpv is coming up with -0.728333 for time-pos.

For audio/video playback IINA is using libmpv. When a problem reproduces with mpv like this for IINA it is an "upstream" problem that needs to be reported to the mpv project. Normally I'd go ahead and do that, but I am currently super busy. If you can do that it would be helpful. If not, I will try and remember to come back to this issue and get that done.