TriForceX / MiyooCFW

Custom firmware source code and resources for BittBoy, PocketGo, PowKiddy V90-Q90-Q20 and third party handheld consoles
GNU General Public License v2.0
1.11k stars 112 forks source link

mplayer resume ability fixed #421

Closed fire-hawk-86 closed 1 year ago

fire-hawk-86 commented 2 years ago

It does not only check if there is a .resume file, but also, if the file is valid. If it's invalid, it will play the video from the start, just as if there was none. If the video is finished, and an invalid .resume file is produced, it will be deleted, just as if it was a legit (End of file).

Explanation: At the end of a video, the return value of mplayer isn't producing the expected output with Exiting... (End of file) as the last line.

I tested it and it works as expected. You don't even have to delete any .resume files manually.

edit main/apps/mplayer/run.sh on your sd-card to the following

#!/bin/sh
RESUME=$(dirname "$1")/.$(basename "$1").resume

EXIT=$(tail -n 1 "$RESUME")

if [ -f "$RESUME" ] && [ "$EXIT" == "Exiting... (Quit)" ]; then
    END=$(cat -v "$RESUME" | tail -3 | head -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs) 
    ./mplayer -ss $END -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
else
    ./mplayer -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
fi

EXIT=$(tail -n 1 "$RESUME")

if [ "$EXIT" == "Exiting... (Quit)" ]; then
    #echo "Quit"

elif [ "$EXIT" == "Exiting... (End of file)" ]; then
    #echo "End"
    rm "$RESUME"
else
    #echo "Broken"
    rm "$RESUME"
fi

Enjoy!

Rezzy-dev commented 2 years ago

There are still bugs with it:

  1. If the video is paused before exiting, Mplayer will crash/quit on next launch, and not be able to resume.

  2. When the video finishes playing and Mplayer automatically exits, the resume file is not removed.

Rezzy-dev commented 2 years ago

First bug fixed:

#!/bin/sh
RESUME=$(dirname "$1")/.$(basename "$1").resume

EXIT=$(tail -n 1 "$RESUME")

PAUSED=$(tail -n 3 "$RESUME" | grep -c "PAUSE")

if [ -f "$RESUME" ] && [ "$EXIT" == "Exiting... (Quit)" ]; then
    if [ "$PAUSED" == 1 ]; then
        END=$(cat -v "$RESUME" | tail -4 | head -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs) 
    else
        END=$(cat -v "$RESUME" | tail -3 | head -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs) 
    fi
    ./mplayer -ss $END -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
else
    ./mplayer -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
fi

EXIT=$(tail -n 1 "$RESUME")

if [ "$EXIT" == "Exiting... (Quit)" ]; then
    #echo "Quit"

elif [ "$EXIT" == "Exiting... (End of file)" ]; then
    #echo "End"
    rm "$RESUME"
else
    #echo "Broken"
    rm "$RESUME"
fi
fire-hawk-86 commented 2 years ago

Add a : below #echo "Quit".

if [ "$EXIT" == "Exiting... (Quit)" ]; then
    #echo "Quit"
    :

That's where the elif bug comes from, because it expects at least one command. The : functions as a placeholder command, that is not doing anything. This is one of the reasons why the .resume files weren't deleted. The shell script doesn't even get that far, because of that error.

Rezzy-dev commented 2 years ago

You're correct! :smiley:

The following code fixes both bugs:

#!/bin/sh
RESUME=$(dirname "$1")/.$(basename "$1").resume

EXIT=$(tail -n 1 "$RESUME")

PAUSED=$(tail -n 3 "$RESUME" | grep -c "PAUSE")

if [ -f "$RESUME" ] && [ "$EXIT" == "Exiting... (Quit)" ]; then
    if [ "$PAUSED" == 1 ]; then
        END=$(cat -v "$RESUME" | tail -4 | head -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs) 
    else
        END=$(cat -v "$RESUME" | tail -3 | head -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs) 
    fi
    ./mplayer -ss $END -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
else
    ./mplayer -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
fi

EXIT=$(tail -n 1 "$RESUME")

if [ "$EXIT" == "Exiting... (Quit)" ]; then
    #echo "Quit"
    :
elif [ "$EXIT" == "Exiting... (End of file)" ]; then
    #echo "End"
    rm "$RESUME"
else
    #echo "Broken"
    rm "$RESUME"
fi
Rezzy-dev commented 2 years ago

It can actually be simplified with:

#!/bin/sh
RESUME=$(dirname "$1")/.$(basename "$1").resume

EXIT=$(tail -n 1 "$RESUME")

PAUSED=$(tail -n 3 "$RESUME" | grep -c "PAUSE")

if [ -f "$RESUME" ] && [ "$EXIT" == "Exiting... (Quit)" ]; then
    if [ "$PAUSED" == 1 ]; then
        END=$(cat -v "$RESUME" | tail -4 | head -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs) 
    else
        END=$(cat -v "$RESUME" | tail -3 | head -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs) 
    fi
    ./mplayer -ss $END -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
else
    ./mplayer -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee "$RESUME"
fi

EXIT=$(tail -n 1 "$RESUME")

if [ "$EXIT" != "Exiting... (Quit)" ]; then
    rm "$RESUME"
fi

Since we don't need to keep the resume file if the playback was not in progress and properly saved.

Rezzy-dev commented 2 years ago

Hmm... :thinking: Wouldn't it be simpler and more reliable to simply grep for the line with the last instance of "V:" instead of using tail to try and guess where the line is located in the file?

$(grep "V:" "$RESUME" | tail -n 1)

This would allow us to resume playback even if a clean shutdown didn't take place -- if the resume file is corrupted.

Rezzy-dev commented 2 years ago

Here is a more forwards-compatible and better documented and optimised version of this script. One that doesn't continually write to the SD card as you're watching (prolonging your SD card's life):

#!/bin/sh

# Set resume file path
RESUMEFILE=$(dirname "$1")/.$(basename "$1").resume

# Get resume states from resume file
RESUMES=$(cat -v "$RESUMEFILE" | grep " V:")

# Set resume time
START=00:00:00

if [ -f "$RESUMEFILE" ] && [ "$RESUMES" != "" ]; then
    START=$(echo "$RESUMES" | tail -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs)
fi

unset RESUMES

# Start playback
RESUMESTATE=$(./mplayer -ss $START -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee /dev/tty)

# Check whether to save state on exit
SAVEVALID=false
SAVECOND=$(echo "$RESUMESTATE" | grep -c "Exiting... (Quit)")
#SAVECOND=$(echo "$RESUMESTATE" | grep -c "End of file")

if [ "$SAVECOND" != 0 ]; then
    SAVEVALID=true
fi

# Save resume state, or remove save file
if [ "$SAVEVALID" == true ]; then
    echo "$RESUMESTATE" > "$RESUMEFILE"
elif [ -f "$RESUMEFILE" ]; then
    rm "$RESUMEFILE"
fi

unset RESUMESTATE

It's set to save the resume state whenever you quit Mplayer (until you've reached the end of the video).


Alternatively, if you want Mplayer to save the resume state on every single occasion (even when it force-quits or crashes) except when you've reached the end of the file (finished watching the video), then swap the SAVEVALID and SAVECOND values in this section, like so:

# Check whether to save state on exit
SAVEVALID=true
#SAVECOND=$(echo "$RESUMESTATE" | grep -c "Exiting... (Quit)")
SAVECOND=$(echo "$RESUMESTATE" | grep -c "End of file")

if [ "$SAVECOND" != 0 ]; then
    SAVEVALID=false
fi

Mplayer is now able to resume playback even from a badly/differently formatted resume save (so long as the timestamps are there).

fire-hawk-86 commented 2 years ago

I've recently encoded a couple of movies for the PocketGo. But sadly they the audio and video were going out of sync constantly, then you have to "fast forward" or "rewind" to fix it, until it goes out of sync again. This issue seems to be fixed completely now.

I think that had to do with the constant writing to the .resume file, before the fix. Thanks.

Rezzy-dev commented 2 years ago

Could be -- the continuous writing to the SD card would also impose a throttle on the read-write (data transfer) speed of the card, and how much data can pass through at once.

Also, use these settings when converting videos for Miyoo:

Encoding: MPEG-4 Resolution: 320x240 (240p) Video Bitrate: 1024 (or less) kbps Framerate: 20 fps

See here for guidance/tips: https://github.com/TriForceX/MiyooCFW/discussions/351

Rezzy-dev commented 2 years ago

For anyone using and testing this script (the latter one), I'd be interested to hear how it performs on lengthier videos, over 2 hours long. There is one potential drawback with this method, and that is that the resume state is being stored in the RAM until Mplayer exits, and that there's a limit to how much data can be stored in memory.

I'm pretty certain it will hold up fine, but, nonetheless, I'd be interested to hear if anyone notices any issues with very long audios or videos.

Rezzy-dev commented 2 years ago

Okay, I've just tested a 2 and a half hour long, 1.3 GB size film. These are my experiences/observations:

(Considering we're working with only 32 MB of RAM here as the only available system memory, that's not bad at all!)

50 minutes of watching a film produced about 3 MB of save data (which was successfully written to disk). Therefore watching a 2.5 hour long film, if the device can handle the whole thing in one session, will produce about 9 MB of save data in Mplayer (to be stored in memory and written to the disk).

If anyone has any other experiences, let me know.

Rezzy-dev commented 2 years ago

Here's an update to the script to add audio file resume support as well (when there's no video to play):

#!/bin/sh

# Set resume file path
RESUMEFILE=$(dirname "$1")/.$(basename "$1").resume

# Get resume states from resume file
RESUMES=$(cat -v "$RESUMEFILE" | grep "A:")
NOVIDEO=$(cat -v "$RESUMEFILE" | grep -c "no video")

# Set resume time
START=00:00:00

if [ -f "$RESUMEFILE" ] && [ "$RESUMES" != "" ]; then
    if [ "$NOVIDEO" != 0 ]; then
        START=$(echo "$RESUMES" | tail -1 | sed 's/.*A://' | cut -d"(" -f1 | xargs)
    else
        START=$(echo "$RESUMES" | tail -1 | sed 's/.*\ V://' | cut -dA -f1 | xargs)
    fi
fi

unset RESUMES

# Start playback
RESUMESTATE=$(./mplayer -ss $START -ao alsa -vo sdl -vf scale -zoom -xy 320 -screenw 320 -screenh 240 "$1" | tee /dev/tty)

# Check whether to save state on exit
SAVEVALID=false
SAVECOND=$(echo "$RESUMESTATE" | grep -c "Exiting... (Quit)")
#SAVECOND=$(echo "$RESUMESTATE" | grep -c "End of file")

if [ "$SAVECOND" != 0 ]; then
    SAVEVALID=true
fi

# Save resume state, or remove save file
if [ "$SAVEVALID" == true ]; then
    echo "$RESUMESTATE" > "$RESUMEFILE"
elif [ -f "$RESUMEFILE" ]; then
    rm "$RESUMEFILE"
fi

unset RESUMESTATE

Mplayer can now be used to listen to audiobooks as well (and save progress).

oop128 commented 2 years ago

thank you - It seems to be working for me - very much appreciated