@@ -40,9 +40,6 @@ class PythonAdapters
40
40
otio::SerializableObject::Retainer<otio::Timeline> const &,
41
41
std::string const &,
42
42
otio::ErrorStatus*);
43
-
44
- private:
45
- bool _convert (std::string const & in_file_name, std::string const & out_file_name);
46
43
};
47
44
48
45
PythonAdapters::PythonAdapters ()
@@ -55,53 +52,122 @@ PythonAdapters::~PythonAdapters()
55
52
Py_Finalize ();
56
53
}
57
54
55
+ class PyObjectRef
56
+ {
57
+ public:
58
+ PyObjectRef (PyObject* o) :
59
+ o (o)
60
+ {
61
+ if (!o)
62
+ {
63
+ throw std::runtime_error (" Python error" );
64
+ }
65
+ }
66
+
67
+ ~PyObjectRef ()
68
+ {
69
+ Py_XDECREF (o);
70
+ }
71
+
72
+ PyObject* o = nullptr ;
73
+
74
+ operator PyObject* () const { return o; }
75
+ };
76
+
58
77
otio::SerializableObject::Retainer<otio::Timeline> PythonAdapters::read_from_file (
59
78
std::string const & file_name,
60
79
otio::ErrorStatus* error_status)
61
80
{
62
- // Convert the input file to a temporary JSON file.
63
- const std::string temp_file_name = create_temp_dir () + " /temp.otio" ;
64
- if (!_convert (file_name, temp_file_name))
81
+ otio::SerializableObject::Retainer<otio::Timeline> timeline;
82
+ try
83
+ {
84
+ // Import the OTIO Python module.
85
+ auto p_module = PyObjectRef (PyImport_ImportModule (" opentimelineio.adapters" ));
86
+
87
+ // Read the timeline into Python.
88
+ auto p_read_from_file = PyObjectRef (PyObject_GetAttrString (p_module, " read_from_file" ));
89
+ auto p_read_from_file_args = PyObjectRef (PyTuple_New (1 ));
90
+ const std::string file_name_normalized = normalize_path (file_name);
91
+ auto p_read_from_file_arg = PyUnicode_FromStringAndSize (file_name_normalized.c_str (), file_name_normalized.size ());
92
+ if (!p_read_from_file_arg)
93
+ {
94
+ throw std::runtime_error (" cannot create arg" );
95
+ }
96
+ PyTuple_SetItem (p_read_from_file_args, 0 , p_read_from_file_arg);
97
+ auto p_timeline = PyObjectRef (PyObject_CallObject (p_read_from_file, p_read_from_file_args));
98
+
99
+ // Convert the Python timeline into a string and use that to create a C++ timeline.
100
+ auto p_to_json_string = PyObjectRef (PyObject_GetAttrString (p_timeline, " to_json_string" ));
101
+ auto p_json_string = PyObjectRef (PyObject_CallObject (p_to_json_string, NULL ));
102
+ timeline = otio::SerializableObject::Retainer<otio::Timeline>(
103
+ dynamic_cast <otio::Timeline*>(otio::Timeline::from_json_string (
104
+ PyUnicode_AsUTF8AndSize (p_json_string, NULL ),
105
+ error_status)));
106
+ }
107
+ catch (const std::exception& e)
65
108
{
66
109
error_status->outcome = otio::ErrorStatus::Outcome::FILE_OPEN_FAILED;
67
- error_status->details = " cannot read file: " + file_name;
68
- return nullptr ;
110
+ error_status->details = e.what ();
69
111
}
70
-
71
- // Read the timeline from the temporary JSON file.
72
- return dynamic_cast <otio::Timeline*>(otio::Timeline::from_json_file (temp_file_name, error_status));
112
+ if (PyErr_Occurred ())
113
+ {
114
+ PyErr_Print ();
115
+ }
116
+ return timeline;
73
117
}
74
118
75
119
bool PythonAdapters::write_to_file (
76
120
otio::SerializableObject::Retainer<otio::Timeline> const & timeline,
77
121
std::string const & file_name,
78
122
otio::ErrorStatus* error_status)
79
123
{
80
- // Write the timeline to a temporary JSON file.
81
- const std::string temp_file_name = create_temp_dir () + " /temp.otio" ;
82
- if (!timeline.value ->to_json_file (temp_file_name, error_status))
124
+ bool r = false ;
125
+ try
83
126
{
84
- return false ;
127
+ // Import the OTIO Python module.
128
+ auto p_module = PyObjectRef (PyImport_ImportModule (" opentimelineio.adapters" ));
129
+
130
+ // Convert the C++ timeline to a string and pass that to Python.
131
+ const auto string = timeline.value ->to_json_string (error_status);
132
+ if (error_status->outcome != otio::ErrorStatus::Outcome::OK)
133
+ {
134
+ throw std::runtime_error (" cannot convert to string" );
135
+ }
136
+ auto p_read_from_string = PyObjectRef (PyObject_GetAttrString (p_module, " read_from_string" ));
137
+ auto p_read_from_string_args = PyObjectRef (PyTuple_New (1 ));
138
+ auto p_read_from_string_arg = PyUnicode_FromStringAndSize (string.c_str (), string.size ());
139
+ if (!p_read_from_string_arg)
140
+ {
141
+ throw std::runtime_error (" cannot create arg" );
142
+ }
143
+ PyTuple_SetItem (p_read_from_string_args, 0 , p_read_from_string_arg);
144
+ auto p_timeline = PyObjectRef (PyObject_CallObject (p_read_from_string, p_read_from_string_args));
145
+
146
+ // Write the Python timeline.
147
+ auto p_write_to_file = PyObjectRef (PyObject_GetAttrString (p_module, " write_to_file" ));
148
+ auto p_write_to_file_args = PyObjectRef (PyTuple_New (2 ));
149
+ const std::string file_name_normalized = normalize_path (file_name);
150
+ auto p_write_to_file_arg = PyUnicode_FromStringAndSize (file_name_normalized.c_str (), file_name_normalized.size ());
151
+ if (!p_write_to_file_arg)
152
+ {
153
+ throw std::runtime_error (" cannot create arg" );
154
+ }
155
+ PyTuple_SetItem (p_write_to_file_args, 0 , p_timeline);
156
+ PyTuple_SetItem (p_write_to_file_args, 1 , p_write_to_file_arg);
157
+ PyObjectRef (PyObject_CallObject (p_write_to_file, p_write_to_file_args));
158
+
159
+ r = true ;
85
160
}
86
-
87
- // Convert the temporary JSON file to the output file.
88
- if (!_convert (temp_file_name, file_name))
161
+ catch (const std::exception& e)
89
162
{
90
163
error_status->outcome = otio::ErrorStatus::Outcome::FILE_WRITE_FAILED;
91
- error_status->details = " cannot write file: " + file_name;
92
- return false ;
164
+ error_status->details = e.what ();
93
165
}
94
-
95
- return true ;
96
- }
97
-
98
- bool PythonAdapters::_convert (const std::string& inFileName, const std::string& outFileName)
99
- {
100
- std::stringstream ss;
101
- ss << " import opentimelineio as otio\n " ;
102
- ss << " timeline = otio.adapters.read_from_file('" << normalize_path (inFileName) << " ')\n " ;
103
- ss << " otio.adapters.write_to_file(timeline, '" << normalize_path (outFileName) << " ')\n " ;
104
- return 0 == PyRun_SimpleString (ss.str ().c_str ());
166
+ if (PyErr_Occurred ())
167
+ {
168
+ PyErr_Print ();
169
+ }
170
+ return r;
105
171
}
106
172
107
173
int main (int argc, char ** argv)
0 commit comments