-
Notifications
You must be signed in to change notification settings - Fork 11
Editorial_pkg: publishing sequence into OTIO timeline with rendered media #132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Editorial_pkg: publishing sequence into OTIO timeline with rendered media #132
Conversation
…ot render out the frame first, and make sure the product name unique
…implement the functions for storing the relevant editorial data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a call with Kayla I am adding some notes for the workflow improvements
extract_intermediate_representation
- add settings for the plugin containing:
- output extension - with validation for video type only restriction
- custom ffmpeg args list
- representation tag list
- representation custom tags list
- gets rendered exrs sequence
- converts exrs to settings defined output file
- use the output file as representation for integration
- this representation only is used in
extract_editorial_packageplugin for otio ExternalRepresentations
extract_editorial_package
- make sure all clips are having ExternalRepresentations inherited from
extract_intermediate_representationwith correct trim framerange - all media source paths should be relative to published otio file representation
- find a way to pass sequence item's unique identifyer to otio clip metadata (this will be later used for loading and edit synchronization)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry but still not working when trying to load the editorial pckg into Resolve...
I will provide both otio and publish report too for inspection.
And publish report:
UE-Editorial-publish-report-250922-15-33.json.txt
QD_unreal_editorial_pkgMain_v006.otio.txt
Note: It could be loaded manually via native File > Import Timeline as seen on the scrncap below, also note missing burnins on the source mp4 file (Ayon didnt incorporate any)
|
@jakubjezek001 can you review? |
|
@moonyuet I did re-test it but still no luck.... no burnins and cant Ayon load the editorial into Resolve... no good news, sry |
…a to identify clips and tracks in unreal
|
The updated commit includes the clips and tracks with unreal-specific metadata to identify the clips and tracks(They get different names with some version numbers) |
| def _extract_intermediate( | ||
| self, instance, input_frames, render_dir, extension, ffmpeg_args): | ||
| """Extract the intermediate representation for the instance. | ||
|
|
||
| Args: | ||
| instance (pyblish.api.Instance): The instance to extract. | ||
| input_frames (list): List of input frame file paths. | ||
| render_dir (str): The directory where the rendered files are located. | ||
| extension (str): The file extension for the intermediate representation. | ||
| ffpmeg_args (dict): Dictionary which stores the list of additional ffmpeg arguments. | ||
| """ | ||
| collection = pipeline.get_sequence_by_collection(input_frames)[0] | ||
| in_frame_start = min(collection.indexes) | ||
| # converting image sequence to image sequence | ||
| input_file = collection.format("{head}{padding}{tail}") | ||
| input_path = os.path.join(render_dir, input_file) | ||
| output_path = os.path.join(render_dir, f"{instance.name}.{extension}") | ||
| sequence_fps = instance.data["fps"] | ||
| input_args = ffmpeg_args.get("input", []) | ||
| default_input_args = [ | ||
| "-start_number", str(in_frame_start), | ||
| "-framerate", str(sequence_fps), | ||
| ] | ||
| if input_args: | ||
| default_input_args.extend(input_args) | ||
| default_input_args.extend(["-i", input_path]) | ||
| all_intput_args = self._split_ffmpeg_args(default_input_args) | ||
| output_args = ffmpeg_args.get("output", []) | ||
| video_filters = ffmpeg_args.get("video_filters", []) | ||
| audio_filters = ffmpeg_args.get("audio_filters", []) | ||
|
|
||
| output_args = self._split_ffmpeg_args(output_args) | ||
| video_args_dentifiers = ["-vf", "-filter:v"] | ||
| audio_args_dentifiers = ["-af", "-filter:a"] | ||
| for arg in tuple(output_args): | ||
| for identifier in video_args_dentifiers: | ||
| if arg.startswith("{} ".format(identifier)): | ||
| output_args.remove(arg) | ||
| arg = arg.replace(identifier, "").strip() | ||
| video_filters.append(arg) | ||
|
|
||
| for identifier in audio_args_dentifiers: | ||
| if arg.startswith("{} ".format(identifier)): | ||
| output_args.remove(arg) | ||
| arg = arg.replace(identifier, "").strip() | ||
| audio_filters.append(arg) | ||
|
|
||
| all_args = [ | ||
| subprocess.list2cmdline(get_ffmpeg_tool_args("ffmpeg")) | ||
| ] | ||
| all_args.extend(all_intput_args) | ||
| if video_filters: | ||
| all_args.append("-filter:v") | ||
| all_args.append("\"{}\"".format(",".join(video_filters))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iLLiCiTiT could you have a look please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for late response, not sure what should I be looking at?
| try: | ||
| project = get_current_project_name() | ||
| anatomy = Anatomy(project) | ||
| root = anatomy.roots['renders'] | ||
| except Exception as e: | ||
| raise Exception(( | ||
| "Could not find render root " | ||
| "in anatomy settings.")) from e | ||
| render_dir = f"{root}/{project}/editorial_pkg/{instance.data.get('output')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| try: | |
| project = get_current_project_name() | |
| anatomy = Anatomy(project) | |
| root = anatomy.roots['renders'] | |
| except Exception as e: | |
| raise Exception(( | |
| "Could not find render root " | |
| "in anatomy settings.")) from e | |
| render_dir = f"{root}/{project}/editorial_pkg/{instance.data.get('output')}" | |
| anatomy = instance.context.data["anatomy"] | |
| try: | |
| root = anatomy.roots['renders'] | |
| except Exception as e: | |
| raise Exception(( | |
| "Could not find render root " | |
| "in anatomy settings.")) from e | |
| render_dir = f"{root}/{anatomy.project_name}/editorial_pkg/{instance.data.get('output')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is forcing studio to have "renders" root. That probably should be settings related?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this is the current state where the renders root is really enforced. We need to change it to "normal" anatomy templates for Unreal with some sane defaults, but not in this PR. So there should be setting to select proper anatomy template.
The issue is that in Unreal, you don't want to have renders in Unreal project, you need them somewhere else.
client/ayon_unreal/plugins/publish/extract_intermediate_representation.py
Outdated
Show resolved
Hide resolved
| try: | ||
| project = get_current_project_name() | ||
| anatomy = Anatomy(project) | ||
| root = anatomy.roots['renders'] | ||
| except Exception as e: | ||
| raise Exception(( | ||
| "Could not find render root " | ||
| "in anatomy settings.")) from e | ||
|
|
||
| render_dir = f"{root}/{project}/editorial_pkg/{data.get('output')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| try: | |
| project = get_current_project_name() | |
| anatomy = Anatomy(project) | |
| root = anatomy.roots['renders'] | |
| except Exception as e: | |
| raise Exception(( | |
| "Could not find render root " | |
| "in anatomy settings.")) from e | |
| render_dir = f"{root}/{project}/editorial_pkg/{data.get('output')}" | |
| anatomy = instance.context.data["anatomy"] | |
| try: | |
| root = anatomy.roots['renders'] | |
| except Exception as e: | |
| raise Exception(( | |
| "Could not find render root " | |
| "in anatomy settings.")) from e | |
| render_dir = f"{root}/{anatomy.project_name}/editorial_pkg/{data.get('output')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question as above, the root should be in settings.
If the path is "hardcoded" (which seems as it is), it probably should be passed along instead of calculating it again at all the places?
Co-authored-by: Jakub Trllo <[email protected]>
Co-authored-by: Jakub Trllo <[email protected]>
Changelog Description
Implement a sequence-based workflow for publishing an editorial package in Unreal. This workflow should publish the OTIO timeline and an intermediate render in MP4 format.
Resolve #131,
Resolve #125
Resolve #124
unreal_export.pyedited for the otio implementationAdditional info
-It may need multiple testing to get the correct frame ranges
@jakubjezek001 this is the zipped file with otio and the clip:
il_UE_editorial_pkgMain_v006.zip
Testing notes: