Puedo descargar los JPG de mi carpeta DCIM en mi Pixel 2 y sé que el vídeo está codificado dentro del jpg, pero no sé qué visor de imágenes puedo utilizar para ver el movimiento. Suelo usar Irfanview, pero aún no he conseguido averiguar cómo hacer que muestre el movimiento. Y no he encontrado a nadie que hable de cómo hacerlo. ¿Alguien sabe?
Respuestas
¿Demasiados anuncios?Hice algunos experimentos basados en el post de @jameshenstridge y llegué a un simple PHP script que dividió con éxito cada foto de google motion que le lancé.
<?php
$src_arg = $argv[1];
$src_dir = realpath(pathinfo($src_arg, PATHINFO_DIRNAME));
echo "Scanning for files...\n";
foreach (glob($src_arg) as $src) {
$file = realpath($src);
if (!is_dir($file) && in_array(strtoupper(pathinfo($file, PATHINFO_EXTENSION)), ["JPEG", "JPG"])) {
echo "\tProcessing: " . $file . "\n";
$filesize = filesize($file);
echo "\t\tFile size: " . $filesize . "\n";
$handle = fopen($file, "rb");
$data = fread($handle, $filesize);
fclose($handle);
$eoi_pos = strpos($data, "\xFF\xD9\x00\x00\x00\x18");
echo "\t\tEOI segment position: " . $eoi_pos . "\n";
if ($eoi_pos !== FALSE) {
$output_base = $src_dir . DIRECTORY_SEPARATOR . pathinfo($file, PATHINFO_FILENAME);
echo "\t\tSaving photo...\n";
file_put_contents($output_base . "_photo.jpg", substr($data, 0, $eoi_pos + 2));
echo "\t\tSaving video...\n";
file_put_contents($output_base . "_video.mp4", substr($data, $eoi_pos + 2));
} else {
echo "\t\tSKIPPING - File does not appear to be a Google motion photo.\n";
}
}
}
echo "Done.\n";
?>
Debería funcionar en Windows y Linux. Sólo tienes que pasar una ruta como primer argumento y dividirá los archivos que crea que son fotos en movimiento. Puedes utilizar comodines. No es destructivo - el archivo(s) de origen no se elimina.
Algunos ejemplos de uso:
php google_motion_photo_splitter.php c:\test\file.jpg
php google_motion_photo_splitter.php c:\test\*.jpg
php google_motion_photo_splitter.php c:\test\*
No he visto ningún programa para verlas que no sea en el sitio web de Google Photos. Tenía curiosidad por esto, así que empecé a desmontar una de las fotos de mi teléfono, y esto es lo que encontré:
-
El archivo de imagen parece ser una imagen JPEG estándar, pero continúa después del Fin del segmento de imagen (
0xFF 0xD9
). -
exiftool
informa de MakerNotes no reconocidos. Sospecho que estos metadatos personalizados identifican el archivo como una foto de movimiento. -
Si transfieres todos los datos después del segmento EOI a un archivo separado, tendrás un contenedor MPEG-4 estándar. Obtuve un fallo de GStreamer al intentar reproducirlo, pero ffmpeg parece ser capaz de manejarlo y mostró los siguientes metadatos:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'foo.mp4': Metadata: major_brand : mp42 minor_version : 0 compatible_brands: isommp42 creation_time : 2018-07-07T20:37:57.000000Z com.android.version: 8.1.0 Duration: 00:00:01.87, start: 0.000000, bitrate: 20283 kb/s Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, smpte170m/smpte170m/unknown), 1024x768, 20161 kb/s, SAR 1:1 DAR 4:3, 30.01 fps, 30 tbr, 90k tbn, 180k tbc (default) Metadata: creation_time : 2018-07-07T20:37:57.000000Z handler_name : VideoHandle Stream #0:1(eng): Data: none (mett / 0x7474656D), 108 kb/s (default) Metadata: creation_time : 2018-07-07T20:37:57.000000Z handler_name : MetadHandle Stream #0:2(eng): Data: none (mett / 0x7474656D), 0 kb/s (default) Metadata: creation_time : 2018-07-07T20:37:57.000000Z handler_name : MetadHandle Unsupported codec with id 0 for input stream 1 Unsupported codec with id 0 for input stream 2
Por lo tanto, se trata de un vídeo H.264 de 1,87 segundos con una resolución de 1024x768, que parece coincidir aproximadamente con lo que veo en las aplicaciones/sitio web de Google (una caída de la resolución y un cambio en la relación de aspecto).
Sé que no es una solución completa, pero podría ser suficiente para empezar con una herramienta para extraer los vídeos.
Aunque la pregunta es para Windows, creo que es apropiado publicar aquí mi script para reproducirlo desde línea de comandos en Linux:
https://gist.github.com/vi/5de17bb8d4ea91b8c28e79e0bac6c3cb
#!/bin/bash
if [[ -z "$1" || "$1" == --help || "$1" == "-?" ]]; then
echo "Usage: mvimg_play MVIMG_20190806_183324.jpg [other files]"
echo "Plays Google's Motion Photo using mpv. Depends on exiftool, mktemp, bash and mpv."
exit 0
fi
FOUND=0
ARGS=()
TORM=()
TOKILL=()
function cleanup() {
for i in "${TORM[@]}"; do
rm -f "$i"
done
for p in ${TOKILL[@]}; do
wait $p
done
}
trap "cleanup" EXIT
for i in "$@"; do
O=$(exiftool -t $i | grep -F 'Micro Video Offset' | cut -f 2-2)
if [[ -z "$O" ]]; then
# wrong file? Just appending to playlist as is
ARGS+=($i)
else
FOUND=1
S=$(find $i -printf '%s')
T=`mktemp`
ARGS+=("$T")
dd if="$i" skip=$((S-O)) iflag=skip_bytes of="$T" 2> /dev/null &
TOKILL+=($!)
TORM+=("$T")
fi
done
if [[ $FOUND == 0 ]]; then
echo "EXIF tag wasn't detected in specified files. Maybe exiftool does not work?" >&2
fi
mpv "${ARGS[@]}"
Tal vez se pueda usar también en Windows, con suficiente hacking de Mingw/Cygwin.
También hay Visor de fotos en movimiento . Puede ser auto-alojado o utilizado en línea para jugar un solo *.MP.jpg
(y extraer el mp4 a través de right-click-save-as
.
No necesitas un servidor web, así que clonar el proyecto y abrir index.html
será suficiente.
He probado la respuesta de Kory más arriba - gracias Kory. Como mi Pixel 4a 5G añade una cantidad significativa de información de depuración entre el jpg y el mp4, mis mp4 extraídos no se reproducían.
Así que tuve que añadir un poco de funcionalidad extra a la solución de Kory
<?php
/** execute like > php motionPhotoSplitter.php "Camera Roll/*.MP.jpg" < */
const MP4_TYPES = ["avc1", "iso2", "isom", "mmp4", "mp41", "mp42", "mp71", "msnv", "ndas", "ndsc", "ndsh", "ndsm", "ndsp", "ndss", "ndxc", "ndxh", "ndxm", "ndxp", "ndxs"];
$src_arg = $argv[1];
$src_dir = realpath(pathinfo($src_arg, PATHINFO_DIRNAME));
echo "Scanning for files...\n";
foreach (glob($src_arg) as $src) {
$file = realpath($src);
if (!is_dir($file) && in_array(strtoupper(pathinfo($file, PATHINFO_EXTENSION)), ["JPEG", "JPG"])) {
echo "\tProcessing: " . $file . "\n";
$filesize = filesize($file);
echo "\t\tFile size: " . $filesize . "\n";
$handle = fopen($file, "rb"); // binary read
$data = fread($handle, $filesize);
fclose($handle);
$eoi_pos = strpos($data, "\xFF\xD9"); // end of image in a jpeg file: #FFD9
echo "\t\tEOI segment position: " . $eoi_pos . "\n";
if ($eoi_pos !== FALSE) {
$output_base = $src_dir . DIRECTORY_SEPARATOR . pathinfo($file, PATHINFO_FILENAME);
echo "\t\tSaving photo...\n";
file_put_contents($output_base . "_photo.jpg", substr($data, 0, $eoi_pos + 2));
/** an mp4 block starts with 4 bytes for length, then "ftyp", then a valid mp4-type as defined in the array MP4_TYPES */
$mp4Pos = strpos($data, "ftyp", $eoi_pos);
if ($mp4Pos && in_array(substr($data, $mp4Pos + 4, 4), MP4_TYPES)) {
echo "\t\tSaving video...\n";
file_put_contents($output_base . "_video.mp4", substr($data, $mp4Pos - 4));
}
} else {
echo "\t\tSKIPPING - File does not appear to be a Google motion photo.\n";
}
}
}
echo "Done.\n";
?>