motionphoto


Namemotionphoto JSON
Version 0.1.2 PyPI version JSON
download
home_pagehttps://github.com/doodspav/motionphoto
SummaryPython library for creating Google and Samsung compatible Motion Photos
upload_time2024-04-19 19:40:41
maintainerNone
docs_urlNone
authordoodspav
requires_python<4,>=3.8
licenseNone
keywords livephoto livephoto motionphoto motionphoto
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # motionphoto
Python library for creating Google and Samsung compatible Motion Photos.

Most notably this can be used to convert Live Photos downloaded from iCloud 
(where each photo comes as a separate image and video file) into Motion Photos that users
with Android can use.

## Table of Contents
<!--ts-->
* [Installation](#installation)
* [Usage](#usage)
* [Motion Photo Format](#motion-photo-format)
  * [Google](#google)
  * [Samsung](#samsung)
* [Future](#future)
<!--te-->

## Installation

Linux/MacOS:
```shell
$ python3 -m pip install motionphoto
```

Windows:
```shell
$ py -m pip install motionphoto
```

This library has a dependency on `exiftool`.

Instructions for installing it can be found [here](https://exiftool.org/install.html) and it must be available on
`PATH`, or it can be installed with a package manager.

## Usage

`motionphoto -i <imagePath> -v <videoPath> -m <outputPath> [-t_us <keyFrameOffset> --overwrite]`

Notes:
- `<imagePath>` image format must be JPEG
- `<keyFrameOffset>` is where the image is, in microseconds, from the start of the video file
- `--overwrite` flag allows overwriting an existing file instead of returning an error

## Motion Photo Format
This section will cover the requirements to make a valid Motion Photo.  
Since each application/vendor has their own implementation, they also have separate requirements.

The image format should be JPEG, not HEIC. HEIC occassionally works, but is not reliable.

### Google
Google requires that the video file be embedded inside the image file, however no requirements are
placed on how this should be done. The video file is commonly appended to the end of the image file.

#### Photos
The Google Photos app requires, at a minimum, the following metadata tags to be set on the image:
- `MicroVideo`: set to `1`
- `MicroVideoVersion`: this library sets it to `1`
- `MicroVideoOffset`: offset in bytes from the end of the Motion Photo file to the start of the embedded video file

The offset is encoded as an XML field, so it does not impose any limit on the video size.

The additional metadata tag may be optionally set if known, may be set to `-1` if unknown, or may
be omitted entirely:
- `MicroVideoPresentationTimestampUs`: key-frame time offset in microseconds

#### Gallery
The Google Gallery app additionally requires that the Motion Photo filename start with `MV`.

### Samsung
Samsung requires that the video file be embedded inside the image file by constructing a trailer in a custom
format and appending it to the end of the image file.  
It **MUST** be the last trailer in the image file.

#### Trailer Data
Trailer fields are written sequentially in the following format:
```
[\x00\x00][marker_value(ule16)][name_size(ule32)][name][data]
```
In our case we want:
```
                  name size              raw video file
                     ∨∨                      ∨∨∨∨∨
[\x00\x00][\x30\x0A][16]["MotionPhoto_Data"][<bin>]
 ∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧      ∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧
       marker                   name
```
Additional fields can be found [here](https://github.com/exiftool/exiftool/blob/ecc573fc04ac6538802fd0a61a9c4ca53837ca1d/lib/Image/ExifTool/Samsung.pm#L945)
but are not necessary.

#### Trailer Check
The trailer also has an additional SEF section that contains the sizes of fields and is used for validation.
It is appended directly after the fields, and has the following format:  
```
["SEFH"][version(ule32)][field_count(ule32)]
for each field: [\x00\x00][field_marker_value(ule16)][field_offset_from_sef(ule32)][field_size(ule32)]
[sef_size(ule32)]["SEFT"]
```
The `sef_size` is the size of that whole section not including `"SEFH"` and `"SEFT"` (head and tail markers).

In our case (assuming `tsbsef` is the trailer size before SEF) we want:
```
  head      count      marker                field size      tail
  ∨∨∨∨        ∨  ∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨            ∨∨∨∨∨∨∨       ∨∨∨∨
["SEFH"][106][1][\x00\x00][\x30\x0A][<tsbsef>][<tsbef>][24]["SEFT"]
         ∧∧∧                         ∧∧∧∧∧∧∧∧           ∧∧
       version                     field offset       sef size
```

#### Metadata
The following metadata tags may optionally be set:
- `MotionPhoto`: set to `1`
- `MotionPhotoVersion`: this library sets it to `1`
- `MotionPhotoPresentationTimestampUs`: key-frame time offset in microseconds

Samsung does not place any requirements on the file name.

## Future:
- attempt to parse key frame timestamp from Live Photo (discussed [here]())
- write `XMP-Container:Directory` data for Samsung (discussed [here](https://github.com/exiftool/exiftool/issues/254))
- add support for working with whole directories


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/doodspav/motionphoto",
    "name": "motionphoto",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4,>=3.8",
    "maintainer_email": null,
    "keywords": "livephoto, LivePhoto, motionphoto, MotionPhoto",
    "author": "doodspav",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/c6/eb/737a1d385694a6a3bc7c1acf6510b0b7434b1e43fcbe2923602a0e626bcd/motionphoto-0.1.2.tar.gz",
    "platform": "any",
    "description": "# motionphoto\nPython library for creating Google and Samsung compatible Motion Photos.\n\nMost notably this can be used to convert Live Photos downloaded from iCloud \n(where each photo comes as a separate image and video file) into Motion Photos that users\nwith Android can use.\n\n## Table of Contents\n<!--ts-->\n* [Installation](#installation)\n* [Usage](#usage)\n* [Motion Photo Format](#motion-photo-format)\n  * [Google](#google)\n  * [Samsung](#samsung)\n* [Future](#future)\n<!--te-->\n\n## Installation\n\nLinux/MacOS:\n```shell\n$ python3 -m pip install motionphoto\n```\n\nWindows:\n```shell\n$ py -m pip install motionphoto\n```\n\nThis library has a dependency on `exiftool`.\n\nInstructions for installing it can be found [here](https://exiftool.org/install.html) and it must be available on\n`PATH`, or it can be installed with a package manager.\n\n## Usage\n\n`motionphoto -i <imagePath> -v <videoPath> -m <outputPath> [-t_us <keyFrameOffset> --overwrite]`\n\nNotes:\n- `<imagePath>` image format must be JPEG\n- `<keyFrameOffset>` is where the image is, in microseconds, from the start of the video file\n- `--overwrite` flag allows overwriting an existing file instead of returning an error\n\n## Motion Photo Format\nThis section will cover the requirements to make a valid Motion Photo.  \nSince each application/vendor has their own implementation, they also have separate requirements.\n\nThe image format should be JPEG, not HEIC. HEIC occassionally works, but is not reliable.\n\n### Google\nGoogle requires that the video file be embedded inside the image file, however no requirements are\nplaced on how this should be done. The video file is commonly appended to the end of the image file.\n\n#### Photos\nThe Google Photos app requires, at a minimum, the following metadata tags to be set on the image:\n- `MicroVideo`: set to `1`\n- `MicroVideoVersion`: this library sets it to `1`\n- `MicroVideoOffset`: offset in bytes from the end of the Motion Photo file to the start of the embedded video file\n\nThe offset is encoded as an XML field, so it does not impose any limit on the video size.\n\nThe additional metadata tag may be optionally set if known, may be set to `-1` if unknown, or may\nbe omitted entirely:\n- `MicroVideoPresentationTimestampUs`: key-frame time offset in microseconds\n\n#### Gallery\nThe Google Gallery app additionally requires that the Motion Photo filename start with `MV`.\n\n### Samsung\nSamsung requires that the video file be embedded inside the image file by constructing a trailer in a custom\nformat and appending it to the end of the image file.  \nIt **MUST** be the last trailer in the image file.\n\n#### Trailer Data\nTrailer fields are written sequentially in the following format:\n```\n[\\x00\\x00][marker_value(ule16)][name_size(ule32)][name][data]\n```\nIn our case we want:\n```\n                  name size              raw video file\n                     \u2228\u2228                      \u2228\u2228\u2228\u2228\u2228\n[\\x00\\x00][\\x30\\x0A][16][\"MotionPhoto_Data\"][<bin>]\n \u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227      \u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227\n       marker                   name\n```\nAdditional fields can be found [here](https://github.com/exiftool/exiftool/blob/ecc573fc04ac6538802fd0a61a9c4ca53837ca1d/lib/Image/ExifTool/Samsung.pm#L945)\nbut are not necessary.\n\n#### Trailer Check\nThe trailer also has an additional SEF section that contains the sizes of fields and is used for validation.\nIt is appended directly after the fields, and has the following format:  \n```\n[\"SEFH\"][version(ule32)][field_count(ule32)]\nfor each field: [\\x00\\x00][field_marker_value(ule16)][field_offset_from_sef(ule32)][field_size(ule32)]\n[sef_size(ule32)][\"SEFT\"]\n```\nThe `sef_size` is the size of that whole section not including `\"SEFH\"` and `\"SEFT\"` (head and tail markers).\n\nIn our case (assuming `tsbsef` is the trailer size before SEF) we want:\n```\n  head      count      marker                field size      tail\n  \u2228\u2228\u2228\u2228        \u2228  \u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228\u2228            \u2228\u2228\u2228\u2228\u2228\u2228\u2228       \u2228\u2228\u2228\u2228\n[\"SEFH\"][106][1][\\x00\\x00][\\x30\\x0A][<tsbsef>][<tsbef>][24][\"SEFT\"]\n         \u2227\u2227\u2227                         \u2227\u2227\u2227\u2227\u2227\u2227\u2227\u2227           \u2227\u2227\n       version                     field offset       sef size\n```\n\n#### Metadata\nThe following metadata tags may optionally be set:\n- `MotionPhoto`: set to `1`\n- `MotionPhotoVersion`: this library sets it to `1`\n- `MotionPhotoPresentationTimestampUs`: key-frame time offset in microseconds\n\nSamsung does not place any requirements on the file name.\n\n## Future:\n- attempt to parse key frame timestamp from Live Photo (discussed [here]())\n- write `XMP-Container:Directory` data for Samsung (discussed [here](https://github.com/exiftool/exiftool/issues/254))\n- add support for working with whole directories\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Python library for creating Google and Samsung compatible Motion Photos",
    "version": "0.1.2",
    "project_urls": {
        "Download": "https://github.com/doodspav/motionphoto",
        "Homepage": "https://github.com/doodspav/motionphoto",
        "Source": "https://github.com/doodspav/motionphoto"
    },
    "split_keywords": [
        "livephoto",
        " livephoto",
        " motionphoto",
        " motionphoto"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b15239ae886394907ef1c29eea289dcb7952981c658280a0b770fe367a86aa1f",
                "md5": "ac5b7eca73a3d8f2ae766cee1ff91d5e",
                "sha256": "7ba2f2f8536462060ee835ae105ad026339d09594e2f69d449612c665b7c4676"
            },
            "downloads": -1,
            "filename": "motionphoto-0.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ac5b7eca73a3d8f2ae766cee1ff91d5e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4,>=3.8",
            "size": 9454,
            "upload_time": "2024-04-19T19:40:40",
            "upload_time_iso_8601": "2024-04-19T19:40:40.435642Z",
            "url": "https://files.pythonhosted.org/packages/b1/52/39ae886394907ef1c29eea289dcb7952981c658280a0b770fe367a86aa1f/motionphoto-0.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c6eb737a1d385694a6a3bc7c1acf6510b0b7434b1e43fcbe2923602a0e626bcd",
                "md5": "1822c03165c787f6dafffdbbc7699739",
                "sha256": "02d8d7bc7cbea8df718df0c5af68407c70349c7f2f381753cc15cbd54a9580fd"
            },
            "downloads": -1,
            "filename": "motionphoto-0.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "1822c03165c787f6dafffdbbc7699739",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4,>=3.8",
            "size": 9285,
            "upload_time": "2024-04-19T19:40:41",
            "upload_time_iso_8601": "2024-04-19T19:40:41.965752Z",
            "url": "https://files.pythonhosted.org/packages/c6/eb/737a1d385694a6a3bc7c1acf6510b0b7434b1e43fcbe2923602a0e626bcd/motionphoto-0.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-19 19:40:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "doodspav",
    "github_project": "motionphoto",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "motionphoto"
}
        
Elapsed time: 0.53609s