Skip to content

Commit

Permalink
Merge pull request #9 from JaimeFlorian27/multiplatform
Browse files Browse the repository at this point in the history
feat: removed findstr dependency, added linux and mac support.
  • Loading branch information
JaimeFlorian27 authored Apr 21, 2024
2 parents 7567164 + 3919c9b commit d62d5d6
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 72 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ __pycache__/
.Python
build/
bin/
bin_linux/
bin_mac/
bin_windows/
develop-eggs/
dist/
downloads/
Expand Down
70 changes: 44 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,45 @@
# Reference Importer
## Description
Script that automates the importing of video reference into Maya, automatically creating an image sequence from a video file and creating an image plane with the sequence.
# Installation
## 1. Download the correct version from the Releases tab
>If Using Maya 2021 or under, download ***ReferenceImporter.zip***.
>If Using Maya 2022 or higher, download ***ReferenceImporter_Python3.zip***.
## 2. Copy the contents of the zip to you Maya scripts folder
>found under 'Documents/maya/***InsertMayaVerion***/scripts'
## 2. Run the following command in Maya
import reference_importer
reference_importer.run()
make sure to run it using Python

# Usage

## for a demonstration of usage please watch the video :

[![Script Walkthrough Video](https://img.youtube.com/vi/ObX9NU2BmZo/0.jpg)](https://www.youtube.com/watch?v=ObX9NU2BmZo "Script Walkthrough Video")
### 1. Choose a video file
### 2. Set the desired trimming
> Use format HH:MM:SS.ms for the timecode
### 3. Set output sequence name and format
### 4. Set output directory for the sequence
### 5. (Optional) auto creation of image plane in Maya for the sequence
### 6. Import the video!!
Tool to help artists import videos as image sequence in Maya without going through a
video editing package. Supports multiple file formats, length trimming and specifying a
target frame rate.

## Features
- Video to image sequence conversion, for improved Reference Plane performance.
- Automatic frame rate conversion (Forget about using Premiere Pro to change the frame rate of your reference!).
- Automatic creation of a Reference Plane in Maya.
- Multiplatform support (Windows, Mac and Linux).
- [Ffmpeg](https://ffmpeg.org/) as the backend engine for video conversion.
- [Qt.py](https://github.com/mottosso/Qt.py) abstraction for multiple Maya versions support (2022+).

## Installation
1. Find the latest version under the [Releases](https://github.com/JaimeFlorian27/reference-importer/releases) section.
2. Download the right distribution for your platform.
- Distributions use the following naming pattern: `reference_importer_<version>_<platform>.zip`
3. Extract the zip file as a folder named `reference_importer` in your `$MAYA_APP_DIR/<MAYA_VERSION>/scripts` folder.
- ie: `/home/jaime/Maya/2024/scripts/reference_importer`
- [What is my MAYA_APP_DIR?](https://help.autodesk.com/view/MAYAUL/2024/ENU/?guid=GUID-228CCA33-4AFE-4380-8C3D-18D23F7EAC72)

## Usage

To launch Reference Importer, run the following Python script:
```
import reference_importer
reference_importer.run()
```

### Workflow

1. Select a video file in the UI.
2. Set the desired start and end timecode.
- End timecode will be populated by default to the end of the video.
> Use HH:MM:SS.ms as the timecode format.
3. Set output image sequence name.
4. Set the output format.
4. Select the output directory for the sequence.
4. Set the desired target frame rate.
5. (Optional) Enable creation of an Image Plane in Maya for the sequence.
6. Import the video!

#### Demonstration Video:

[![Reference Importer demonstration video](https://img.youtube.com/vi/ObX9NU2BmZo/0.jpg)](https://www.youtube.com/watch?v=ObX9NU2BmZo "Script Walkthrough Video")
13 changes: 9 additions & 4 deletions ReferenceImporterMain.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
# Video Demonstration: https://www.youtube.com/watch?v=ObX9NU2BmZo

import sys
import os
import platform
from pathlib import Path

# Allow standalone to show in macOS
if platform.system() == "Darwin":
os.environ["QT_MAC_WANTS_LAYER"] = "1"

VENDOR_PATH = Path(__file__).parent.resolve() / "vendor"
sys.path.insert(0, str(VENDOR_PATH))

import os
import re
from Qt import QtCore,QtWidgets
from Qt.QtCompat import wrapInstance
Expand All @@ -21,7 +26,7 @@
except ImportError:
IN_MAYA = False

from .reference_importer import ImageSequencer, Ui
from .reference_importer_main import ImageSequencer, Ui



Expand Down Expand Up @@ -94,7 +99,7 @@ def SetInput(self):
filename = filename[0]

if filename != "":
duration = self.imageSequencer.getDuration(filename)
duration = self.imageSequencer.get_duration(filename)
self.ui.lineEdit_end_trim.setText(duration)
self.ui.lineEdit.setText(filename)
def SetOutput(self):
Expand Down Expand Up @@ -155,7 +160,7 @@ def CreateImageSequence(self):
output_name = self.ui.lineEdit_2.text()+"_%03d"+output_ext
output_file = os.path.join(output_dir, output_name)

self.imageSequencer.createSequence(input_file,frameRate,
self.imageSequencer.create_sequence(input_file,frameRate,
trim_start,trim_end,
output_file)

Expand Down
41 changes: 0 additions & 41 deletions reference_importer/imageSequence.py

This file was deleted.

File renamed without changes.
114 changes: 114 additions & 0 deletions reference_importer_main/imageSequence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from __future__ import annotations
import re
import shutil
import subprocess
import platform
from pathlib import Path

TIMECODE_REGEX = r"Duration: (\d{2}:\d{2}:\d{2}.\d)"


class FfmpegError(Exception):
...

class MissingFfmpeg(FfmpegError):
...


class ImageSequencer:
def __init__(
self,
video_file: str = "",
output_name: str = "",
padding: str = "%03d",
output_frame_rate: int = 24,
) -> None:
self.output_frame_rate = output_frame_rate
self.video_file = video_file
self.output_name = output_name
self.padding = padding
self.trim_start = 0
self.trim_end = 0
self.ffmpeg_path = self.get_ffmpeg_path()

@classmethod
def get_ffmpeg_path(cls) -> Path:
"""Resolves the path to ffmpeg.
The script first attempts to use the ffmpeg available in the bin folder,
otherwise it fallbacks to the first match of ffmpeg avaiable in Path.
Raises:
MissingFfmpeg: If no ffmpeg binaries are available.
"""
_ffmpeg_binary = f"ffmpeg{'.exe' if platform.system() == 'Windows' else ''}"
ffmpeg_executable = Path(__file__).parent.parent.resolve() / "bin" / _ffmpeg_binary
if not ffmpeg_executable.exists():
ffmpeg_executable = shutil.which("ffmpeg")

if not ffmpeg_executable:
raise MissingFfmpeg()
return Path(ffmpeg_executable)

def get_duration(self, video_file: str) -> str:
"""Gets the duration of the video from the output of ffmpeg -i.
Args:
video_file: Video file.
Raises:
FfmpegError: If ffmpeg errors out and does not yield an output.
ValueError: If there is no match for the duration in ffmpeg's output.
Returns:
Duration of the video in timecode.
"""
command = f'"{self.ffmpeg_path}" -i "{video_file}"'
try:
output = str(
subprocess.run(
command,
shell=True,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE,
check=False,
),
)

except subprocess.CalledProcessError as e:
_except_msg: str = "Unable to get ffmpeg output"
raise FfmpegError(_except_msg) from e

# re.search searches across the whole string (multiline output).
match: re.Match | None = re.search(TIMECODE_REGEX, output)

if not match:
_except_msg: str = f"Unable to find Duration for video {video_file}"
raise ValueError(_except_msg)

# the timecode is the first group of the match.
duration: str = str(match.groups(0)[0])
return duration

def create_sequence(
self,
input_file: str,
frame_rate: int,
start_trim: str,
end_trim: str,
output_file: str,
):
command = (
f'"{self.ffmpeg_path}" -i "{input_file}" -r {frame_rate}'
f" -vf scale=1280:-1 -q:v 3 -ss {start_trim} -to {end_trim} "
f'"{output_file}"'
)
try:
subprocess.run(command, shell=True, check=False)
except subprocess.CalledProcessError as e:
raise FfmpegError from e


if __name__ == "__main__":
pass
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def __init__(self, Dialog):
# setupUi

def setTexts(self, Dialog):
Dialog.setWindowTitle(u"Reference Importer v1.1.2")
Dialog.setWindowTitle(u"Reference Importer v1.2.0")
self.groupBox_input.setTitle(u"Input")
self.label_video_file.setText(u"Video File")
self.pushButton_fileExplorer_input.setText(u"Open...")
Expand Down
File renamed without changes.

0 comments on commit d62d5d6

Please sign in to comment.