server icon indicating copy to clipboard operation
server copied to clipboard

[Bug]: Movie preview not generated on remote storages if file > 5MiB

Open Digit-al opened this issue 7 months ago • 6 comments

⚠️ This issue respects the following points: ⚠️

Bug description

Since this change on 23-Apr (https://github.com/nextcloud/server/commit/4a924bf400c7015bb337188fc14e1a0cb77a8d0a), I have no preview generated for Movies uploaded from my phone on my personal space which is a remote storage (NAS). I have no local storage on the nextcloud host. I switched back to the previous version of Movie.php and the preview are generated again.

Steps to reproduce

  1. configure the root space of a user as external storage (SMB on a NAS)
  2. use nextcloud client to auto upload picture & movies from the phone to InstanUpload dir
  3. there is no preview generated for the movies and the error displayed in the log is : {"reqId":"MpJdE6WUzPxfeo8SisaJ","level":3,"time":"2025-06-10T14:17:00+00:00","remoteAddr":"77.131.3.199","user":"user","app":"core","method":"GET","url":"/index.php/core/preview?fileId=8234197&x=256&y=256&a=1&mode=cover&forceIcon=0","message":"Failed to get local file to generate thumbnail for: /user/files/Tmp/Test/PXL_20250610_140337908.mp4","userAgent":"Mozilla/5.0 (Android) Nextcloud-android/3.31.4","version":"31.0.5.1","data":{"app":"core"},"id":"684c15862c051"}

Expected behavior

The preview must be produced as it was with the previous version

Nextcloud Server version

31

Operating system

Debian/Ubuntu

PHP engine version

PHP 8.3

Web server

Apache (supported)

Database engine version

MariaDB

Is this bug present after an update or on a fresh install?

Updated from a MINOR version (ex. 32.0.1 to 32.0.2)

Are you using the Nextcloud Server Encryption module?

None

What user-backends are you using?

  • [ ] Default user-backend (database)
  • [x] LDAP/ Active Directory
  • [ ] SSO - SAML
  • [ ] Other

Configuration report

root@nextcloud:~# sudo -u www-data php /var/www/html/occ config:list system
{
    "system": {
        "instanceid": "***REMOVED SENSITIVE VALUE***",
        "passwordsalt": "***REMOVED SENSITIVE VALUE***",
        "secret": "***REMOVED SENSITIVE VALUE***",
        "trusted_domains": [
            "192.168.10.221",
            "pvcld.test.tld"
        ],
        "trusted_proxies": "***REMOVED SENSITIVE VALUE***",
        "overwritehost": "pvcld.test.tld",
        "overwriteprotocol": "https",
        "datadirectory": "***REMOVED SENSITIVE VALUE***",
        "dbtype": "mysql",
        "version": "31.0.5.1",
        "overwrite.cli.url": "http:\/\/192.168.10.221",
        "dbname": "***REMOVED SENSITIVE VALUE***",
        "dbhost": "***REMOVED SENSITIVE VALUE***",
        "dbport": "",
        "dbtableprefix": "oc_",
        "mysql.utf8mb4": true,
        "dbuser": "***REMOVED SENSITIVE VALUE***",
        "dbpassword": "***REMOVED SENSITIVE VALUE***",
        "installed": true,
        "mail_from_address": "***REMOVED SENSITIVE VALUE***",
        "mail_smtpmode": "smtp",
        "mail_sendmailmode": "smtp",
        "mail_domain": "***REMOVED SENSITIVE VALUE***",
        "mail_smtpsecure": "tls",
        "mail_smtpauth": 1,
        "mail_smtpport": "587",
        "mail_smtphost": "***REMOVED SENSITIVE VALUE***",
        "mail_smtpname": "***REMOVED SENSITIVE VALUE***",
        "mail_smtppassword": "***REMOVED SENSITIVE VALUE***",
        "default_phone_region": "FR",
        "memcache.local": "\\OC\\Memcache\\Redis",
        "memcache.distributed": "\\OC\\Memcache\\Redis",
        "filelocking.enabled": true,
        "memcache.locking": "\\OC\\Memcache\\Redis",
        "redis": {
            "host": "***REMOVED SENSITIVE VALUE***",
            "port": 0
        },
        "maintenance": false,
        "maintenance_window_start": 1,
        "ldapProviderFactory": "OCA\\User_LDAP\\LDAPProviderFactory",
        "enable_previews": true,
        "preview_max_x": 1024,
        "preview_max_y": 768,
        "preview_max_scale_factor": 1,
        "preview_ffmpeg_path": "\/usr\/bin\/ffmpeg",
        "enabledPreviewProviders": [
            "OC\\Preview\\IMAGE",
            "OC\\Preview\\Movie",
            "OC\\Preview\\GIF",
            "OC\\Preview\\BMP",
            "OC\\Preview\\XBitmap",
            "OC\\Preview\\MP3",
            "OC\\Preview\\TXT",
            "OC\\Preview\\MarkDown",
            "OC\\Preview\\OpenDocument",
            "OC\\Preview\\PDF",
            "OC\\Preview\\MP4",
            "OC\\Preview\\MOV",
            "OC\\Preview\\MKV",
            "OC\\Preview\\HEIC",
            "OC\\Preview\\JPEG",
            "OC\\Preview\\PNG",
            "OC\\Preview\\AVI"
        ],
        "theme": "",
        "loglevel": 2,
        "memories.db.triggers.fcu": true,
        "memories.exiftool": "\/var\/www\/html\/apps\/memories\/bin-ext\/exiftool-amd64-glibc",
        "memories.vod.path": "\/var\/www\/html\/apps\/memories\/bin-ext\/go-vod-amd64",
        "memories.vod.ffmpeg": "\/usr\/bin\/ffmpeg",
        "memories.vod.ffprobe": "\/usr\/bin\/ffprobe",
        "memories.index.mode": "1",
        "memories.index.path": "\/",
        "memories.index.path.blacklist": "\\\/(Movies|Scans)\\\/",
        "memories.gis_type": 1,
        "files.chunked_upload.max_size": 20971520,
        "app_install_overwrite": [
            "officeonline",
            "maps"
        ]
    }
}

List of activated Apps

root@nextcloud:~# sudo -u www-data php /var/www/html/occ app:list
Enabled:
  - activity: 4.0.0
  - app_api: 5.0.2
  - bruteforcesettings: 4.0.0
  - checksum: 1.2.6
  - cloud_federation_api: 1.14.0
  - contactsinteraction: 1.12.0
  - dav: 1.33.0
  - external: 6.0.2
  - federatedfilesharing: 1.21.0
  - files: 2.3.1
  - files_downloadlimit: 4.0.0
  - files_external: 1.23.0
  - files_pdfviewer: 4.0.0
  - files_reminders: 1.4.0
  - files_sharing: 1.23.1
  - files_trashbin: 1.21.0
  - files_versions: 1.24.0
  - logreader: 4.0.0
  - lookup_server_connector: 1.19.0
  - maps: 1.5.0
  - memories: 7.5.2
  - nextcloud_announcements: 3.0.0
  - notes: 4.12.0
  - notifications: 4.0.0
  - oauth2: 1.19.1
  - oidc_login: 3.2.2
  - photos: 4.0.0-dev.1
  - previewgenerator: 5.8.0
  - profile: 1.0.0
  - provisioning_api: 1.21.0
  - serverinfo: 3.0.0
  - settings: 1.14.0
  - sharebymail: 1.21.0
  - suspicious_login: 9.0.1
  - text: 5.0.0
  - theming: 2.6.1
  - twofactor_backupcodes: 1.20.0
  - twofactor_totp: 13.0.0-dev.0
  - updatenotification: 1.21.0
  - user_ldap: 1.22.0
  - user_status: 1.11.0
  - viewer: 4.0.0
  - webhook_listeners: 1.2.0
  - workflowengine: 2.13.0
Disabled:
  - admin_audit: 1.21.0
  - assistant: 2.4.0 (installed 2.4.0)
  - calendar: 5.2.2 (installed 5.2.2)
  - camerarawpreviews: 0.8.6 (installed 0.8.6)
  - circles: 31.0.0 (installed 25.0.0)
  - comments: 1.21.0 (installed 1.15.0)
  - contacts: 7.0.6 (installed 7.0.6)
  - context_chat: 4.2.0 (installed 4.2.0)
  - dashboard: 7.11.0 (installed 7.7.0)
  - encryption: 2.19.0
  - federation: 1.21.0 (installed 1.15.0)
  - files_downloadactivity: 1.18.1 (installed 1.18.1)
  - firstrunwizard: 4.0.0 (installed 2.14.0)
  - mail: 5.0.2 (installed 5.0.2)
  - officeonline: 3.0.1 (installed 3.0.1)
  - onlyoffice: 9.8.0 (installed 9.8.0)
  - password_policy: 3.0.0 (installed 1.15.0)
  - privacy: 3.0.0 (installed 1.9.0)
  - recommendations: 4.0.0 (installed 1.4.0)
  - related_resources: 2.0.0 (installed 1.0.3)
  - spreed: 21.0.3 (installed 21.0.3)
  - support: 3.0.0 (installed 1.8.0)
  - survey_client: 3.0.0 (installed 1.13.0)
  - systemtags: 1.21.1 (installed 1.15.0)
  - text2image_stablediffusion: 2.0.0 (installed 2.0.0)
  - twofactor_nextcloud_notification: 5.0.0
  - user_oidc: 7.1.0 (installed 7.1.0)
  - weather_status: 1.11.0 (installed 1.5.0)

Nextcloud Signing status

No errors have been found.

Nextcloud Logs

{"reqId":"MpJdE6WUzPxfeo8SisaJ","level":3,"time":"2025-06-10T14:17:00+00:00","remoteAddr":"77.131.3.199","user":"user","app":"core","method":"GET","url":"/index.php/core/preview?fileId=8234197&x=256&y=256&a=1&mode=cover&forceIcon=0","message":"Failed to get local file to generate thumbnail for: /user/files/Tmp/Test/PXL_20250610_140337908.mp4","userAgent":"Mozilla/5.0 (Android) Nextcloud-android/3.31.4","version":"31.0.5.1","data":{"app":"core"},"id":"684c15862c051"}

Additional info

No response

Digit-al avatar Jun 13 '25 12:06 Digit-al

Based on the log entry + code this seems more like a temporary file creation problem in your environment for some reason. You're right that that commit did change behavior, but the log entry you provided only appears if the preview creation is attempted. The log entry indicates things didn't even get as far as creating it though.

We added additional logging for that situation + there was also some refactoring of the TempManager around the same time.

I'm wondering if #51203 introduced something here that impacts your environment.

Any chance you also have any log entries that say something like Can not create a temporary file in directory {dir}. Check it exists and has correct permissions?

joshtrichards avatar Jun 13 '25 14:06 joshtrichards

Hi @joshtrichards ,

You are right, the error message seems unrelated. However the issue is reproduceable 100%. What I did:

  • 1 - put back the original version of ./lib/private/Preview/Movie.php
  • 2 - remove nextcloud.log
  • 3 - reboot
  • 4 - upload a test file to a test folder (on my root external storage, see picture 1)
  • 5 - no preview generated (picture 2)
  • 6 - nexcloud.log : 0 byte
  • 7 - Modify ./lib/private/Preview/Movie.php:
72c72
<                       //if ($file->getStorage()->isLocal()) {
---
>                       if ($file->getStorage()->isLocal()) {
74,76c74,76
<                       //} else {
<                       //      $sizeAttempts = [5242880];
<                       //}
---
>                       } else {
>                               $sizeAttempts = [5242880];
>                       }

  • 8 - reboot
  • 9 - preview is generated (picture 3)
  • 10 - nexcloud.log : 0 byte

picture 1: Image

picture 2: Image

picture 3: Image

Digit-al avatar Jun 14 '25 05:06 Digit-al

Well, the (actual) code indeed will prevent any files larger than 5MiB on any remote (files_external, S3...) to be generated.

Code is pretty clear:

if ($file->getStorage()->isLocal()) {
    $sizeAttempts = [5242880, null];
} else {
    $sizeAttempts = [5242880];
}

For local storage: The code attempts to generate a thumbnail first by downloading 5 MB (5242880 bytes) of the file, and if that fails, it tries again with the full file (null size).

For non-local storage (e.g., S3): The code only attempts the 5 MB download and does not fall back to downloading the full file.

solracsf avatar Jun 14 '25 08:06 solracsf

I agree, but it breaks it for me so I report it as it's maybe not intentional, and it might break it for others looking for a solution. Maybe you can introduce a config parameter for the user to decide what should be the max size to render preview on remote movies ? I can keep patching the file if you don't want to revert the change.

Digit-al avatar Jun 14 '25 08:06 Digit-al

The only solution here is making it opt-in with a config parameter so files on external storages could have no size limits if the admin wants to parse (download) those, no matter the size of those files.

EDIT : See https://github.com/nextcloud/server/pull/53496#issuecomment-2976680534

solracsf avatar Jun 14 '25 08:06 solracsf

Well, the (actual) code indeed will prevent any files larger than 5MiB on any remote (files_external, S3...) to be generated.

Code is pretty clear:

if ($file->getStorage()->isLocal()) {
    $sizeAttempts = [5242880, null];
} else {
    $sizeAttempts = [5242880];
}

For local storage: The code attempts to generate a thumbnail first by downloading 5 MB (5242880 bytes) of the file, and if that fails, it tries again with the full file (null size).

For non-local storage (e.g., S3): The code only attempts the 5 MB download and does not fall back to downloading the full file.

Background info why it was made #52079

printminion-co avatar Jun 16 '25 07:06 printminion-co

Downloading only a small part of the video is a useful optimization, however it also needs to support video formats that place important data at the end of the file. Instead of downloading only the first 5MB, would be possible to create a sparse file and download the first and last 5MB? The middle of the file would be empty, but ffmpeg should be able to extract a single frame.

I think this issue should be classified as a bug, since video thumbnails are now broken for mp4 files on external storages.

Derkades avatar Jul 12 '25 10:07 Derkades

Downloading only a small part of the video is a useful optimization, however it also needs to support video formats that place important data at the end of the file. Instead of downloading only the first 5MB, would be possible to create a sparse file and download the first and last 5MB? The middle of the file would be empty, but ffmpeg should be able to extract a single frame.

I think this issue should be classified as a bug, since video thumbnails are now broken for mp4 files on external storages.

I've been playing with this but it doesn't work unless I'm doing something wrong. I've taken a known working test.mp4 that has the moov atom located at the end of the file. I made a copy of that file, then truncated the copy to 5,000,000, and then appended 5,000,000 from the original file onto it. ffmpeg will not process the file and cannot locate the moov atom.

What I haven't tried to do is fill in the middle of the file to maintain offsets and see what would happen. I think that's what you're describing? Let me think about this.

edit: Okay, that seems to work. Let me consider how to best to this now.

invario avatar Jul 14 '25 19:07 invario

So one of the problems I'm coming across is the unknown and variable size of the moov atom. For really large files, a moov atom may potentially be several megabytes in size. So this actually be a problem even if the moov atom is located at the front since the current implementation only downloads 5MB of a file from remote and then gives up. The other issue is that if the moov atom is at the back end, doing a tail of 5MB of the file may not be enough either, depending on the length of the video.

For reference during my search, I came across someone with a 9 hour long video and the moov atom was over 32MB large. That's a bit on the extreme end since I don't believe anyone is really using NC and putting 9 hour long videos on. And if they are, what's the point of a single preview/thumbnail taken from the first 5 seconds of the file anyway, so if the preview generation fails...🤷‍♂️

edit: For further reference, the moov atom on a 1.5 hour long 1080p video x264 video I had was approximately 3MB in size.

invario avatar Jul 14 '25 20:07 invario

Downloading only a small part of the video is a useful optimization, however it also needs to support video formats that place important data at the end of the file. Instead of downloading only the first 5MB, would be possible to create a sparse file and download the first and last 5MB? The middle of the file would be empty, but ffmpeg should be able to extract a single frame.

I think this issue should be classified as a bug, since video thumbnails are now broken for mp4 files on external storages.

Thanks to your suggestion, I created PR #53952. I would've preferred my solution to be more robust but... it's better than what's in place right now.

invario avatar Jul 16 '25 00:07 invario

I would like to verify that the fix in #54915 worked flawlessly (I patched my NC instance to include the fix to Movie.php).

Which Nextcloud version will this ship in? Do we have to wait for 32 or will this be in the next bug fix? How can I verify?

Rudd-O avatar Nov 05 '25 11:11 Rudd-O

Can the fix please be backported to 32.0.2? I don't see any indication that this has been backported to stable32 branch. Thanks.

Rudd-O avatar Nov 05 '25 23:11 Rudd-O

Can the fix please be backported to 32.0.2? I don't see any indication that this has been backported to stable32 branch. Thanks.

It is already in 32.

artonge avatar Nov 06 '25 15:11 artonge

Can the fix please be backported to 32.0.2? I don't see any indication that this has been backported to stable32 branch. Thanks.

It is already in 32.

I believe it missed the code freeze for 32 by just a tiny bit.

invario avatar Nov 06 '25 15:11 invario