1 /* ***** BEGIN LICENSE BLOCK *****
2 * This file is part of openfx-io <https://github.com/MrKepzie/openfx-io>,
3 * Copyright (C) 2013-2018 INRIA
4 *
5 * openfx-io is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * openfx-io is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with openfx-io. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
17 * ***** END LICENSE BLOCK ***** */
18
19 /*
20 * OFX ffmpegReader plugin.
21 * Reads a video input file using the libav library.
22 *
23 * Synced with mov64Reader 11.1v3
24 *
25 * BUGS:
26 * - The last frames from long-GOP mp4 don't read, see:
27 * - https://github.com/NatronGitHub/Natron/issues/241
28 * - https://github.com/NatronGitHub/Natron/issues/231
29 * - MPEG1 files cannot be read, for example
30 * - https://github.com/NatronGitHub/Natron-Tests/raw/master/TestReadMPEG1/input.mpg
31 * - http://devernay.free.fr/vision/diffprop/herve3d.mpg
32 * This was already true before the 11.1v3 sync (e.g. at commit 4d0d3a5).
33 */
34
35 #if (defined(_STDINT_H) || defined(_STDINT_H_) || defined(_MSC_STDINT_H_ ) ) && !defined(UINT64_C)
36 #warning "__STDC_CONSTANT_MACROS has to be defined before including <stdint.h>, this file will probably not compile."
37 #endif
38 #ifndef __STDC_CONSTANT_MACROS
39 #define __STDC_CONSTANT_MACROS // ...or stdint.h wont' define UINT64_C, needed by libavutil
40 #endif
41
42 #include <cmath>
43 #include <sstream>
44 #include <algorithm>
45 #ifdef DEBUG
46 #include <cstdio>
47 #define DBG(x) x
48 #else
49 #define DBG(x) (void)0
50 #endif
51
52 #include "IOUtility.h"
53
54 #include "GenericOCIO.h"
55 #include "GenericReader.h"
56 #include "FFmpegFile.h"
57 #include "ofxsCopier.h"
58
59 using namespace OFX;
60 using namespace OFX::IO;
61
62 using std::string;
63 using std::stringstream;
64 using std::vector;
65
66 OFXS_NAMESPACE_ANONYMOUS_ENTER
67
68 #define kPluginName "ReadFFmpeg"
69 #define kPluginGrouping "Image/Readers"
70 #define kPluginDescription "Read video using FFmpeg.\n" \
71 "All formats supported by FFmpeg should be supported, but there may be issues with some non-conform files. In this case, it is recommended to transcode the video to a digital intermediate format, which is more suitable for grading, compositing and video editing.\n" \
72 "This can be done using the ffmpeg command-line tool, by following the instructions at https://trac.ffmpeg.org/wiki/Encode/VFX"
73
74 #define kPluginIdentifier "fr.inria.openfx.ReadFFmpeg"
75 #define kPluginVersionMajor 1 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
76 #define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.
77 #define kPluginEvaluation 0
78
79 #define kParamMaxRetries "maxRetries"
80 #define kParamMaxRetriesLabel "Max retries per frame"
81 #define kParamMaxRetriesHint "Some video files are sometimes tricky to read and needs several retries before successfully decoding a frame. This" \
82 " parameter controls how many times we should attempt to decode the same frame before failing. "
83
84 #define kParamFirstTrackOnly "firstTrackOnly"
85 #define kParamFirstTrackOnlyLabelAndHint "First Track Only", "Causes the reader to ignore all but the first video track it finds in the file. This should be selected in a multiview project if the file happens to contain multiple video tracks that don't correspond to different views."
86
87 #define kParamLibraryInfo "libraryInfo"
88 #define kParamLibraryInfoLabel "FFmpeg Info...", "Display information about the underlying library."
89
90
91 #define kSupportsRGBA true
92 #define kSupportsRGB true
93 #define kSupportsXY false
94 #define kSupportsAlpha false
95 #define kSupportsTiles false
96
97
98 class ReadFFmpegPlugin
99 : public GenericReaderPlugin
100 {
101 FFmpegFileManager& _manager;
102 IntParam *_maxRetries;
103 BooleanParam *_firstTrackOnly;
104
105 public:
106
107 ReadFFmpegPlugin(FFmpegFileManager& manager, OfxImageEffectHandle handle, const vector<string>& extensions);
108
109 virtual ~ReadFFmpegPlugin();
110
111 virtual void changedParam(const InstanceChangedArgs &args, const string ¶mName) OVERRIDE FINAL;
112
113 bool loadNearestFrame() const;
114
115 /**
116 * @brief Restore any state from the parameters set
117 * Called from createInstance() and changedParam() (via changedFilename()), must restore the
118 * state of the Reader, such as Choice param options, data members and non-persistent param values.
119 * We don't do this in the ctor of the plug-in since we can't call virtuals yet.
120 * Any derived implementation must call GenericReaderPlugin::restoreStateFromParams() first
121 **/
122 virtual void restoreStateFromParams() OVERRIDE FINAL;
123
124 private:
125
126 virtual bool isVideoStream(const string& filename) OVERRIDE FINAL;
127
128 /**
129 * @brief Called when the input image/video file changed.
130 *
131 * returns true if file exists and parameters successfully guessed, false in case of error.
132 *
133 * This function is only called once: when the filename is first set.
134 *
135 * Besides returning colorspace, premult, components, and componentcount, if it returns true
136 * this function may also set extra format-specific parameters using Param::setValue.
137 * The parameters must not be animated, since their value must remain the same for a whole sequence.
138 *
139 * You shouldn't do any strong processing as this is called on the main thread and
140 * the getRegionOfDefinition() and decode() should open the file in a separate thread.
141 *
142 * The colorspace may be set if available, else a default colorspace is used.
143 *
144 * You must also return the premultiplication state and pixel components of the image.
145 * When reading an image sequence, this is called only for the first image when the user actually selects the new sequence.
146 **/
147 virtual bool guessParamsFromFilename(const string& filename, string *colorspace, PreMultiplicationEnum *filePremult, PixelComponentEnum *components, int *componentCount) OVERRIDE FINAL;
148 virtual void decode(const string& filename, OfxTime time, int view, bool isPlayback, const OfxRectI& renderWindow, float *pixelData, const OfxRectI& bounds, PixelComponentEnum pixelComponents, int pixelComponentCount, int rowBytes) OVERRIDE FINAL;
149 virtual bool getSequenceTimeDomain(const string& filename, OfxRangeI &range) OVERRIDE FINAL;
150 virtual bool getFrameBounds(const string& filename, OfxTime time, int view, OfxRectI *bounds, OfxRectI *format, double *par, string *error, int* tile_width, int* tile_height) OVERRIDE FINAL;
151 virtual bool getFrameRate(const string& filename, double* fps) const OVERRIDE FINAL;
152 };
153
ReadFFmpegPlugin(FFmpegFileManager & manager,OfxImageEffectHandle handle,const vector<string> & extensions)154 ReadFFmpegPlugin::ReadFFmpegPlugin(FFmpegFileManager& manager,
155 OfxImageEffectHandle handle,
156 const vector<string>& extensions)
157 : GenericReaderPlugin(handle, extensions, kSupportsRGBA, kSupportsRGB, kSupportsXY, kSupportsAlpha, kSupportsTiles, false)
158 , _manager(manager)
159 , _maxRetries(NULL)
160 , _firstTrackOnly(NULL)
161 {
162 _maxRetries = fetchIntParam(kParamMaxRetries);
163 _firstTrackOnly = fetchBooleanParam(kParamFirstTrackOnly);
164 assert(_maxRetries && _firstTrackOnly);
165 int originalFrameRangeMin, originalFrameRangeMax;
166 _originalFrameRange->getValue(originalFrameRangeMin, originalFrameRangeMax);
167 if (originalFrameRangeMin == 0) {
168 // probably a buggy instance from before Jan 19 2015, where 0 is the first frame
169 _originalFrameRange->setValue(originalFrameRangeMin + 1, originalFrameRangeMax + 1);
170 int timeOffset;
171 _timeOffset->getValue(timeOffset);
172 _timeOffset->setValue(timeOffset - 1);
173 }
174 }
175
~ReadFFmpegPlugin()176 ReadFFmpegPlugin::~ReadFFmpegPlugin()
177 {
178 }
179
180 /**
181 * @brief Restore any state from the parameters set
182 * Called from createInstance() and changedParam() (via changedFilename()), must restore the
183 * state of the Reader, such as Choice param options, data members and non-persistent param values.
184 * We don't do this in the ctor of the plug-in since we can't call virtuals yet.
185 * Any derived implementation must call GenericReaderPlugin::restoreStateFromParams() first
186 **/
187 void
restoreStateFromParams()188 ReadFFmpegPlugin::restoreStateFromParams()
189 {
190 GenericReaderPlugin::restoreStateFromParams();
191 //_manager.getOrCreate(this, filename);
192 }
193
194 bool
loadNearestFrame() const195 ReadFFmpegPlugin::loadNearestFrame() const
196 {
197 int v;
198
199 _missingFrameParam->getValue(v);
200
201 return v == 0;
202 }
203
204
205 static string
ffmpeg_versions()206 ffmpeg_versions()
207 {
208 std::ostringstream oss;
209 #ifdef FFMS_USE_FFMPEG_COMPAT
210 oss << "FFmpeg ";
211 #else
212 oss << "libav";
213 #endif
214 oss << " versions (compiled with / running with):" << std::endl;
215 oss << "libavformat ";
216 oss << LIBAVFORMAT_VERSION_MAJOR << '.' << LIBAVFORMAT_VERSION_MINOR << '.' << LIBAVFORMAT_VERSION_MICRO << " / ";
217 oss << (avformat_version() >> 16) << '.' << (avformat_version() >> 8 & 0xff) << '.' << (avformat_version() & 0xff) << std::endl;
218 //oss << "libavdevice ";
219 //oss << LIBAVDEVICE_VERSION_MAJOR << '.' << LIBAVDEVICE_VERSION_MINOR << '.' << LIBAVDEVICE_VERSION_MICRO << " / ";
220 //oss << avdevice_version() >> 16 << '.' << avdevice_version() >> 8 & 0xff << '.' << avdevice_version() & 0xff << std::endl;
221 oss << "libavcodec ";
222 oss << LIBAVCODEC_VERSION_MAJOR << '.' << LIBAVCODEC_VERSION_MINOR << '.' << LIBAVCODEC_VERSION_MICRO << " / ";
223 oss << (avcodec_version() >> 16) << '.' << (avcodec_version() >> 8 & 0xff) << '.' << (avcodec_version() & 0xff) << std::endl;
224 oss << "libavutil ";
225 oss << LIBAVUTIL_VERSION_MAJOR << '.' << LIBAVUTIL_VERSION_MINOR << '.' << LIBAVUTIL_VERSION_MICRO << " / ";
226 oss << (avutil_version() >> 16) << '.' << (avutil_version() >> 8 & 0xff) << '.' << (avutil_version() & 0xff) << std::endl;
227 oss << "libswscale ";
228 oss << LIBSWSCALE_VERSION_MAJOR << '.' << LIBSWSCALE_VERSION_MINOR << '.' << LIBSWSCALE_VERSION_MICRO << " / ";
229 oss << (swscale_version() >> 16) << '.' << (swscale_version() >> 8 & 0xff) << '.' << (swscale_version() & 0xff) << std::endl;
230
231 return oss.str();
232 }
233
234
235 void
changedParam(const InstanceChangedArgs & args,const string & paramName)236 ReadFFmpegPlugin::changedParam(const InstanceChangedArgs &args,
237 const string ¶mName)
238 {
239 if (paramName == kParamLibraryInfo) {
240 sendMessage(Message::eMessageMessage, "", ffmpeg_versions());
241 } else {
242 GenericReaderPlugin::changedParam(args, paramName);
243 }
244 }
245
246 /**
247 * @brief Called when the input image/video file changed.
248 *
249 * returns true if file exists and parameters successfully guessed, false in case of error.
250 *
251 * This function is only called once: when the filename is first set.
252 *
253 * Besides returning colorspace, premult, components, and componentcount, if it returns true
254 * this function may also set extra format-specific parameters using Param::setValue.
255 * The parameters must not be animated, since their value must remain the same for a whole sequence.
256 *
257 * You shouldn't do any strong processing as this is called on the main thread and
258 * the getRegionOfDefinition() and decode() should open the file in a separate thread.
259 *
260 * The colorspace may be set if available, else a default colorspace is used.
261 *
262 * You must also return the premultiplication state and pixel components of the image.
263 * When reading an image sequence, this is called only for the first image when the user actually selects the new sequence.
264 **/
265 bool
guessParamsFromFilename(const string & filename,string * colorspace,PreMultiplicationEnum * filePremult,PixelComponentEnum * components,int * componentCount)266 ReadFFmpegPlugin::guessParamsFromFilename(const string& filename,
267 string *colorspace,
268 PreMultiplicationEnum *filePremult,
269 PixelComponentEnum *components,
270 int *componentCount)
271 {
272 assert(colorspace && filePremult && components && componentCount);
273 FFmpegFile* file = _manager.get(this, filename);
274 if (!file) {
275 //Clear all opened files by this plug-in since the user changed the selected file/sequence
276 _manager.clear(this);
277 file = _manager.getOrCreate(this, filename);
278 }
279
280 if ( !file || file->isInvalid() ) {
281 if (file) {
282 //setPersistentMessage(Message::eMessageError, "", file->getError());
283 } else {
284 //setPersistentMessage(Message::eMessageError, "", "Cannot open file.");
285 }
286
287 return false;
288 }
289
290 # ifdef OFX_IO_USING_OCIO
291 // Unless otherwise specified, video files are assumed to be rec709.
292 if ( _ocio->hasColorspace("Rec709") ) {
293 // nuke-default
294 *colorspace = "Rec709";
295 } else if ( _ocio->hasColorspace("nuke_rec709") ) {
296 // blender
297 *colorspace = "nuke_rec709";
298 } else if ( _ocio->hasColorspace("Rec.709 - Full") ) {
299 // out_rec709full or "Rec.709 - Full" in aces 1.0.0
300 *colorspace = "Rec.709 - Full";
301 } else if ( _ocio->hasColorspace("out_rec709full") ) {
302 // out_rec709full or "Rec.709 - Full" in aces 1.0.0
303 *colorspace = "out_rec709full";
304 } else if ( _ocio->hasColorspace("rrt_rec709_full_100nits") ) {
305 // rrt_rec709_full_100nits in aces 0.7.1
306 *colorspace = "rrt_rec709_full_100nits";
307 } else if ( _ocio->hasColorspace("rrt_rec709") ) {
308 // rrt_rec709 in aces 0.1.1
309 *colorspace = "rrt_rec709";
310 } else if ( _ocio->hasColorspace("hd10") ) {
311 // hd10 in spi-anim and spi-vfx
312 *colorspace = "hd10";
313 }
314 # endif
315
316 *componentCount = file->getNumberOfComponents();
317 *components = (*componentCount > 3) ? ePixelComponentRGBA : ePixelComponentRGB;
318 ///Ffmpeg is RGB opaque.
319 *filePremult = (*componentCount > 3) ? eImageUnPreMultiplied : eImageOpaque;
320
321 return true;
322 } // ReadFFmpegPlugin::guessParamsFromFilename
323
324 bool
isVideoStream(const string & filename)325 ReadFFmpegPlugin::isVideoStream(const string& filename)
326 {
327 return !FFmpegFile::isImageFile(filename);
328 }
329
330 void
decode(const string & filename,OfxTime time,int view,bool,const OfxRectI & renderWindow,float * pixelData,const OfxRectI & imgBounds,PixelComponentEnum pixelComponents,int pixelComponentCount,int rowBytes)331 ReadFFmpegPlugin::decode(const string& filename,
332 OfxTime time,
333 int view,
334 bool /*isPlayback*/,
335 const OfxRectI& renderWindow,
336 float *pixelData,
337 const OfxRectI& imgBounds,
338 PixelComponentEnum pixelComponents,
339 int pixelComponentCount,
340 int rowBytes)
341 {
342 FFmpegFile* file = _manager.getOrCreate(this, filename);
343
344 if ( file && file->isInvalid() ) {
345 setPersistentMessage( Message::eMessageError, "", file->getError() );
346
347 return;
348 }
349 clearPersistentMessage();
350
351 /// we only support RGB or RGBA output clip
352 if ( (pixelComponents != ePixelComponentRGB) &&
353 (pixelComponents != ePixelComponentRGBA) &&
354 (pixelComponents != ePixelComponentAlpha) ) {
355 throwSuiteStatusException(kOfxStatErrFormat);
356
357 return;
358 }
359 assert( (pixelComponents == ePixelComponentRGB && pixelComponentCount == 3) || (pixelComponents == ePixelComponentRGBA && pixelComponentCount == 4) || (pixelComponents == ePixelComponentAlpha && pixelComponentCount == 1) );
360
361 ///blindly ignore the filename, we suppose that the file is the same than the file loaded in the changedParam
362 if (!file) {
363 setPersistentMessage(Message::eMessageError, "", filename + ": Missing frame");
364 throwSuiteStatusException(kOfxStatFailed);
365
366 return;
367 }
368
369 bool firstTrackOnly = _firstTrackOnly->getValueAtTime(time);
370 if (firstTrackOnly) {
371 view = 0;
372 }
373 file->setSelectedStream(view);
374
375 int width, height, frames;
376 double ap;
377 file->getInfo(width, height, ap, frames);
378
379 // wrong assert:
380 // http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#kOfxImageEffectPropSupportsTiles
381 // "If a clip or plugin does not support tiled images, then the host should supply full RoD images to the effect whenever it fetches one."
382 // The renderWindow itself may or may not be the full image...
383 //assert(kSupportsTiles || (renderWindow.x1 == 0 && renderWindow.x2 == width && renderWindow.y1 == 0 && renderWindow.y2 == height));
384
385 if ( ( (imgBounds.x2 - imgBounds.x1) < width ) ||
386 ( (imgBounds.y2 - imgBounds.y1) < height ) ) {
387 setPersistentMessage(Message::eMessageError, "", "The host provided an image of wrong size, can't decode.");
388 throwSuiteStatusException(kOfxStatFailed);
389
390 return;
391 }
392
393 int maxRetries;
394 _maxRetries->getValue(maxRetries);
395
396 // not in FFmpeg Reader: initialize the output buffer
397 // TODO: use avpicture_get_size? see WriteFFmpeg
398 unsigned int numComponents = file->getNumberOfComponents();
399 assert(numComponents == 3 || numComponents == 4);
400
401 std::size_t sizeOfData = file->getSizeOfData();
402 assert( sizeOfData == sizeof(unsigned char) || sizeOfData == sizeof(unsigned short) );
403
404 int srcRowBytes = width * numComponents * sizeOfData;
405 std::size_t bufferSize = height * srcRowBytes;
406
407 RamBuffer bufferRaii(bufferSize);
408 unsigned char* buffer = bufferRaii.getData();
409 if (!buffer) {
410 throwSuiteStatusException(kOfxStatErrMemory);
411
412 return;
413 }
414 // this is the first stream (in fact the only one we consider for now), allocate the output buffer according to the bitdepth
415
416 try {
417 if ( !file->decode(this, (int)time, loadNearestFrame(), maxRetries, buffer) ) {
418 if ( abort() ) {
419 // decode() probably existed because plugin was aborted
420 return;
421 }
422 setPersistentMessage( Message::eMessageError, "", file->getError() );
423 throwSuiteStatusException(kOfxStatFailed);
424
425 return;
426 }
427 } catch (const std::exception& e) {
428 int choice;
429 _missingFrameParam->getValue(choice);
430 if (choice == 1) { //error
431 setPersistentMessage( Message::eMessageError, "", e.what() );
432 throwSuiteStatusException(kOfxStatFailed);
433
434 return;
435 }
436
437 return;
438 }
439
440
441 convertDepthAndComponents(buffer, renderWindow, imgBounds, numComponents == 3 ? ePixelComponentRGB : ePixelComponentRGBA, sizeOfData == sizeof(unsigned char) ? eBitDepthUByte : eBitDepthUShort, srcRowBytes, pixelData, imgBounds, pixelComponents, rowBytes);
442 } // ReadFFmpegPlugin::decode
443
444 bool
getSequenceTimeDomain(const string & filename,OfxRangeI & range)445 ReadFFmpegPlugin::getSequenceTimeDomain(const string& filename,
446 OfxRangeI &range)
447 {
448 if ( FFmpegFile::isImageFile(filename) ) {
449 range.min = range.max = 0.;
450
451 return false;
452 }
453
454 int width, height, frames;
455 double ap;
456 FFmpegFile* file = _manager.getOrCreate(this, filename);
457 if ( !file || file->isInvalid() ) {
458 range.min = range.max = 0.;
459
460 return false;
461 }
462 file->getInfo(width, height, ap, frames);
463
464 range.min = 1;
465 range.max = frames;
466
467 return true;
468 }
469
470 bool
getFrameRate(const string & filename,double * fps) const471 ReadFFmpegPlugin::getFrameRate(const string& filename,
472 double* fps) const
473 {
474 assert(fps);
475
476 FFmpegFile* file = _manager.getOrCreate(this, filename);
477 if ( !file || file->isInvalid() ) {
478 return false;
479 }
480
481 bool gotFps = file->getFPS(*fps);
482
483 return gotFps;
484 }
485
486 bool
getFrameBounds(const string & filename,OfxTime time,int view,OfxRectI * bounds,OfxRectI * format,double * par,string * error,int * tile_width,int * tile_height)487 ReadFFmpegPlugin::getFrameBounds(const string& filename,
488 OfxTime time,
489 int view,
490 OfxRectI *bounds,
491 OfxRectI *format,
492 double *par,
493 string *error,
494 int* tile_width,
495 int* tile_height)
496 {
497 assert(bounds && par);
498 FFmpegFile* file = _manager.getOrCreate(this, filename);
499 if ( !file || file->isInvalid() ) {
500 if (error && file) {
501 *error = file->getError();
502 }
503
504 return false;
505 }
506
507 bool firstTrackOnly = _firstTrackOnly->getValueAtTime(time);
508 if (firstTrackOnly) {
509 view = 0;
510 }
511 file->setSelectedStream(view);
512 int width, height, frames;
513 double ap;
514 if ( !file->getInfo(width, height, ap, frames) ) {
515 width = 0;
516 height = 0;
517 ap = 1.;
518 }
519 bounds->x1 = 0;
520 bounds->x2 = width;
521 bounds->y1 = 0;
522 bounds->y2 = height;
523 *format = *bounds;
524 *par = ap;
525 *tile_width = *tile_height = 0;
526
527 return true;
528 }
529
530 class ReadFFmpegPluginFactory
531 : public PluginFactoryHelper<ReadFFmpegPluginFactory>
532 {
533 auto_ptr<FFmpegFileManager> _manager;
534
535 public:
ReadFFmpegPluginFactory(const string & id,unsigned int verMaj,unsigned int verMin)536 ReadFFmpegPluginFactory(const string& id,
537 unsigned int verMaj,
538 unsigned int verMin)
539 : PluginFactoryHelper<ReadFFmpegPluginFactory>(id, verMaj, verMin)
540 , _manager()
541 {}
542
543 virtual void load() OVERRIDE FINAL;
unload()544 virtual void unload() OVERRIDE FINAL
545 {
546 _manager.reset(NULL);
547 _extensions.clear();
548 }
549
550 virtual ImageEffect* createInstance(OfxImageEffectHandle handle, ContextEnum context) OVERRIDE FINAL;
551
isVideoStreamPlugin() const552 bool isVideoStreamPlugin() const { return true; }
553
554 virtual void describe(ImageEffectDescriptor &desc) OVERRIDE FINAL;
555 virtual void describeInContext(ImageEffectDescriptor &desc, ContextEnum context) OVERRIDE FINAL;
556
557 vector<string> _extensions;
558 };
559
560 #if 0
561 static
562 vector<string> &
563 split(const string &s,
564 char delim,
565 vector<string> &elems)
566 {
567 stringstream ss(s);
568 string item;
569
570 while ( std::getline(ss, item, delim) ) {
571 elems.push_back(item);
572 }
573
574 return elems;
575 }
576
577 #endif
578
579 static
580 std::list<string> &
split(const string & s,char delim,std::list<string> & elems)581 split(const string &s,
582 char delim,
583 std::list<string> &elems)
584 {
585 stringstream ss(s);
586 string item;
587
588 while ( std::getline(ss, item, delim) ) {
589 elems.push_back(item);
590 }
591
592 return elems;
593 }
594
595 #ifdef OFX_IO_MT_FFMPEG
596 static int
FFmpegLockManager(void ** mutex,enum AVLockOp op)597 FFmpegLockManager(void** mutex,
598 enum AVLockOp op)
599 {
600 switch (op) {
601 case AV_LOCK_CREATE: // Create a mutex.
602 try {
603 *mutex = static_cast< void* >(new FFmpegFile::Mutex);
604
605 return 0;
606 }catch (...) {
607 // Return error if mutex creation failed.
608 return 1;
609 }
610
611 case AV_LOCK_OBTAIN: // Lock the specified mutex.
612 try {
613 static_cast< FFmpegFile::Mutex* >(*mutex)->lock();
614
615 return 0;
616 }catch (...) {
617 // Return error if mutex lock failed.
618 return 1;
619 }
620
621 case AV_LOCK_RELEASE: // Unlock the specified mutex.
622 // Mutex unlock can't fail.
623 static_cast< FFmpegFile::Mutex* >(*mutex)->unlock();
624
625 return 0;
626
627 case AV_LOCK_DESTROY: // Destroy the specified mutex.
628 // Mutex destruction can't fail.
629 delete static_cast< FFmpegFile::Mutex* >(*mutex);
630 *mutex = 0;
631
632 return 0;
633
634 default: // Unknown operation.
635 assert(false);
636
637 return 1;
638 }
639 }
640
641 #endif
642
643 void
load()644 ReadFFmpegPluginFactory::load()
645 {
646 _extensions.clear();
647 #if 0
648 // hard-coded extensions list
649 const char* extensionsl[] = { "avi", "flv", "mkv", "webm", "mov", "mp4", "mpg", "m2ts", "mts", "ts", "mxf", "ogv", "r3d", "bmp", "pix", "dpx", "exr", "jpeg", "jpg", "png", "pgm", "ppm", "ptx", "rgba", "rgb", "tiff", "tga", "gif", NULL };
650 for (const char** ext = extensionsl; *ext != NULL; ++ext) {
651 _extensions.push_back(*ext);
652 }
653 #else
654 std::list<string> extensionsl;
655 AVInputFormat* iFormat = av_iformat_next(NULL);
656 while (iFormat != NULL) {
657 //DBG(std::printf("ReadFFmpeg: \"%s\", // %s (%s)\n", iFormat->extensions ? iFormat->extensions : iFormat->name, iFormat->name, iFormat->long_name));
658 if (iFormat->extensions != NULL) {
659 string extStr( iFormat->extensions );
660 split(extStr, ',', extensionsl);
661 }
662 {
663 // name's format defines (in general) extensions
664 // require to fix extension in LibAV/FFMpeg to don't use it.
665 string extStr( iFormat->name);
666 split(extStr, ',', extensionsl);
667 }
668 iFormat = av_iformat_next( iFormat );
669 }
670
671 // Hack: Add basic video container extensions
672 // as some versions of LibAV doesn't declare properly all extensions...
673 // or there may be other well-known extensions (such as mts or m2ts)
674 //extensionsl.push_back("pix"); // alias_pix (Alias/Wavefront PIX image)
675 extensionsl.push_back("avi"); // AVI (Audio Video Interleaved)
676 //extensionsl.push_back("bsa"); // bethsoftvid (Bethesda Softworks VID)
677 //extensionsl.push_back("bik"); // bink (Bink)
678 //extensionsl.push_back("cpk"); // film_cpk (Sega FILM / CPK)
679 //extensionsl.push_back("cak"); // film_cpk (Sega FILM / CPK)
680 //extensionsl.push_back("film"); // film_cpk (Sega FILM / CPK)
681 //extensionsl.push_back("fli"); // flic (FLI/FLC/FLX animation)
682 //extensionsl.push_back("flc"); // flic (FLI/FLC/FLX animation)
683 //extensionsl.push_back("flx"); // flic (FLI/FLC/FLX animation)
684 extensionsl.push_back("flv"); // flv (FLV (Flash Video))
685 //extensionsl.push_back("ilbm"); // iff (IFF (Interchange File Format))
686 //extensionsl.push_back("anim"); // iff (IFF (Interchange File Format))
687 //extensionsl.push_back("mve"); // ipmovie (Interplay MVE)
688 //extensionsl.push_back("lml"); // lmlm4 (raw lmlm4)
689 extensionsl.push_back("mkv"); // matroska,webm (Matroska / WebM)
690 extensionsl.push_back("mk3d"); // matroska,webm (Matroska / WebM)
691 extensionsl.push_back("webm"); // matroska,webm (Matroska / WebM)
692 extensionsl.push_back("mov"); // QuickTime / MOV
693 extensionsl.push_back("mp4"); // MP4 (MPEG-4 Part 14)
694 extensionsl.push_back("mpg"); // MPEG-1 Systems / MPEG program stream
695 extensionsl.push_back("m2ts"); // mpegts (MPEG-TS (MPEG-2 Transport Stream))
696 extensionsl.push_back("mts"); // mpegts (MPEG-TS (MPEG-2 Transport Stream))
697 extensionsl.push_back("ts"); // mpegts (MPEG-TS (MPEG-2 Transport Stream))
698 extensionsl.push_back("mxf"); // mxf (MXF (Material eXchange Format))
699 extensionsl.push_back("ogv"); // ogv (Ogg Video)
700
701 // remove audio and subtitle-only formats
702 const char* extensions_blacklist[] = {
703 "aa", // aa (Audible AA format files)
704 "aac", // aac (raw ADTS AAC (Advanced Audio Coding))
705 "ac3", // ac3 (raw AC-3)
706 "act", // act (ACT Voice file format)
707 // "adf", // adf (Artworx Data Format)
708 "adp", "dtk", // adp (ADP) Audio format used on the Nintendo Gamecube.
709 "adx", // adx (CRI ADX) Audio-only format used in console video games.
710 "aea", // aea (MD STUDIO audio)
711 "afc", // afc (AFC) Audio format used on the Nintendo Gamecube.
712 "aiff", // aiff (Audio IFF)
713 "amr", // amr (3GPP AMR)
714 // "anm", // anm (Deluxe Paint Animation)
715 "apc", // apc (CRYO APC)
716 "ape", "apl", "mac", // ape (Monkey's Audio)
717 // "apng", // apng (Animated Portable Network Graphics)
718 "aqt", "aqtitle", // aqtitle (AQTitle subtitles)
719 // "asf", // asf (ASF (Advanced / Active Streaming Format))
720 // "asf_o", // asf_o (ASF (Advanced / Active Streaming Format))
721 "ass", // ass (SSA (SubStation Alpha) subtitle)
722 "ast", // ast (AST (Audio Stream))
723 "au", // au (Sun AU)
724 // "avi", // avi (AVI (Audio Video Interleaved))
725 "avr", // avr (AVR (Audio Visual Research)) Audio format used on Mac.
726 // "avs", // avs (AVS)
727 // "bethsoftvid", // bethsoftvid (Bethesda Softworks VID)
728 // "bfi", // bfi (Brute Force & Ignorance)
729 "bin", // bin (Binary text)
730 // "bink", // bink (Bink)
731 "bit", // bit (G.729 BIT file format)
732 // "bmv", // bmv (Discworld II BMV)
733 "bfstm", "bcstm", // bfstm (BFSTM (Binary Cafe Stream)) Audio format used on the Nintendo WiiU (based on BRSTM).
734 "brstm", // brstm (BRSTM (Binary Revolution Stream)) Audio format used on the Nintendo Wii.
735 "boa", // boa (Black Ops Audio)
736 // "c93", // c93 (Interplay C93)
737 "caf", // caf (Apple CAF (Core Audio Format))
738 // "cavsvideo", // cavsvideo (raw Chinese AVS (Audio Video Standard))
739 // "cdg", // cdg (CD Graphics)
740 // "cdxl,xl", // cdxl (Commodore CDXL video)
741 // "cine", // cine (Phantom Cine)
742 // "concat", // concat (Virtual concatenation script)
743 // "data", // data (raw data)
744 "302", "daud", // daud (D-Cinema audio)
745 // "dfa", // dfa (Chronomaster DFA)
746 // "dirac", // dirac (raw Dirac)
747 // "dnxhd", // dnxhd (raw DNxHD (SMPTE VC-3))
748 "dsf", // dsf (DSD Stream File (DSF))
749 // "dsicin", // dsicin (Delphine Software International CIN)
750 "dss", // dss (Digital Speech Standard (DSS))
751 "dts", // dts (raw DTS)
752 "dtshd", // dtshd (raw DTS-HD)
753 // "dv,dif", // dv (DV (Digital Video))
754 "dvbsub", // dvbsub (raw dvbsub)
755 // "dxa", // dxa (DXA)
756 // "ea", // ea (Electronic Arts Multimedia)
757 // "cdata", // ea_cdata (Electronic Arts cdata)
758 "eac3", // eac3 (raw E-AC-3)
759 "paf", "fap", "epaf", // epaf (Ensoniq Paris Audio File)
760 "ffm", // ffm (FFM (FFserver live feed))
761 "ffmetadata", // ffmetadata (FFmpeg metadata in text)
762 // "flm", // filmstrip (Adobe Filmstrip)
763 "flac", // flac (raw FLAC)
764 // "flic", // flic (FLI/FLC/FLX animation)
765 // "flv", // flv (FLV (Flash Video))
766 // "flv", // live_flv (live RTMP FLV (Flash Video))
767 // "4xm", // 4xm (4X Technologies)
768 // "frm", // frm (Megalux Frame)
769 "g722", "722", // g722 (raw G.722)
770 "tco", "rco", "g723_1", // g723_1 (G.723.1)
771 "g729", // g729 (G.729 raw format demuxer)
772 // "gif", // gif (CompuServe Graphics Interchange Format (GIF))
773 "gsm", // gsm (raw GSM)
774 // "gxf", // gxf (GXF (General eXchange Format))
775 // "h261", // h261 (raw H.261)
776 // "h263", // h263 (raw H.263)
777 // "h26l,h264,264,avc", // h264 (raw H.264 video)
778 // "hevc,h265,265", // hevc (raw HEVC video)
779 // "hls,applehttp", // hls,applehttp (Apple HTTP Live Streaming)
780 // "hnm", // hnm (Cryo HNM v4)
781 // "ico", // ico (Microsoft Windows ICO)
782 // "idcin", // idcin (id Cinematic)
783 // "idf", // idf (iCE Draw File)
784 // "iff", // iff (IFF (Interchange File Format))
785 "ilbc", // ilbc (iLBC storage)
786 // "image2", // image2 (image2 sequence)
787 "image2pipe", // image2pipe (piped image2 sequence)
788 "alias_pix", // alias_pix (Alias/Wavefront PIX image)
789 "brender_pix", // brender_pix (BRender PIX image)
790 // "cgi", // ingenient (raw Ingenient MJPEG)
791 "ipmovie", // ipmovie (Interplay MVE)
792 "sf", "ircam", // ircam (Berkeley/IRCAM/CARL Sound Format)
793 "iss", // iss (Funcom ISS)
794 // "iv8", // iv8 (IndigoVision 8000 video)
795 // "ivf", // ivf (On2 IVF)
796 "jacosub", // jacosub (JACOsub subtitle format)
797 "jv", // jv (Bitmap Brothers JV)
798 "latm", // latm (raw LOAS/LATM)
799 "lmlm4", // lmlm4 (raw lmlm4)
800 "loas", // loas (LOAS AudioSyncStream)
801 "lrc", // lrc (LRC lyrics)
802 // "lvf", // lvf (LVF)
803 // "lxf", // lxf (VR native stream (LXF))
804 // "m4v", // m4v (raw MPEG-4 video)
805 "mka", "mks", // "mkv,mk3d,mka,mks", // matroska,webm (Matroska / WebM)
806 "mgsts", // mgsts (Metal Gear Solid: The Twin Snakes)
807 "microdvd", // microdvd (MicroDVD subtitle format)
808 // "mjpg,mjpeg,mpo", // mjpeg (raw MJPEG video)
809 "mlp", // mlp (raw MLP)
810 // "mlv", // mlv (Magic Lantern Video (MLV))
811 "mm", // mm (American Laser Games MM)
812 "mmf", // mmf (Yamaha SMAF)
813 "m4a", // "mov,mp4,m4a,3gp,3g2,mj2", // mov,mp4,m4a,3gp,3g2,mj2 (QuickTime / MOV)
814 "mp2", "mp3", "m2a", "mpa", // mp3 (MP2/3 (MPEG audio layer 2/3))
815 "mpc", // mpc (Musepack)
816 "mpc8", // mpc8 (Musepack SV8)
817 // "mpeg", // mpeg (MPEG-PS (MPEG-2 Program Stream))
818 "mpegts", // mpegts (MPEG-TS (MPEG-2 Transport Stream))
819 "mpegtsraw", // mpegtsraw (raw MPEG-TS (MPEG-2 Transport Stream))
820 "mpegvideo", // mpegvideo (raw MPEG video)
821 // "mjpg", // mpjpeg (MIME multipart JPEG)
822 "txt", "mpl2", // mpl2 (MPL2 subtitles)
823 "sub", "mpsub", // mpsub (MPlayer subtitles)
824 "msnwctcp", // msnwctcp (MSN TCP Webcam stream)
825 // "mtv", // mtv (MTV)
826 // "mv", // mv (Silicon Graphics Movie)
827 // "mvi", // mvi (Motion Pixels MVI)
828 // "mxf", // mxf (MXF (Material eXchange Format))
829 // "mxg", // mxg (MxPEG clip)
830 // "v", // nc (NC camera feed)
831 "nist", "sph", "nistsphere", // nistsphere (NIST SPeech HEader REsources)
832 // "nsv", // nsv (Nullsoft Streaming Video)
833 // "nut", // nut (NUT)
834 // "nuv", // nuv (NuppelVideo)
835 // "ogg", // ogg (Ogg)
836 "oma", "omg", "aa3", // oma (Sony OpenMG audio)
837 // "paf", // paf (Amazing Studio Packed Animation File)
838 "al", "alaw", // alaw (PCM A-law)
839 "ul", "mulaw", // mulaw (PCM mu-law)
840 "f64be", // f64be (PCM 64-bit floating-point big-endian)
841 "f64le", // f64le (PCM 64-bit floating-point little-endian)
842 "f32be", // f32be (PCM 32-bit floating-point big-endian)
843 "f32le", // f32le (PCM 32-bit floating-point little-endian)
844 "s32be", // s32be (PCM signed 32-bit big-endian)
845 "s32le", // s32le (PCM signed 32-bit little-endian)
846 "s24be", // s24be (PCM signed 24-bit big-endian)
847 "s24le", // s24le (PCM signed 24-bit little-endian)
848 "s16be", // s16be (PCM signed 16-bit big-endian)
849 "sw", "s16le", // s16le (PCM signed 16-bit little-endian)
850 "sb", "s8", // s8 (PCM signed 8-bit)
851 "u32be", // u32be (PCM unsigned 32-bit big-endian)
852 "u32le", // u32le (PCM unsigned 32-bit little-endian)
853 "u24be", // u24be (PCM unsigned 24-bit big-endian)
854 "u24le", // u24le (PCM unsigned 24-bit little-endian)
855 "u16be", // u16be (PCM unsigned 16-bit big-endian)
856 "uw", "u16le", // u16le (PCM unsigned 16-bit little-endian)
857 "ub", "u8", // u8 (PCM unsigned 8-bit)
858 "pjs", // pjs (PJS (Phoenix Japanimation Society) subtitles)
859 "pmp", // pmp (Playstation Portable PMP)
860 "pva", // pva (TechnoTrend PVA)
861 "pvf", // pvf (PVF (Portable Voice Format))
862 "qcp", // qcp (QCP)
863 // "r3d", // r3d (REDCODE R3D)
864 // "yuv,cif,qcif,rgb", // rawvideo (raw video)
865 "rt", "realtext", // realtext (RealText subtitle format)
866 "rsd", "redspark", // redspark (RedSpark)
867 // "rl2", // rl2 (RL2)
868 // "rm", // rm (RealMedia)
869 // "roq", // roq (id RoQ)
870 // "rpl", // rpl (RPL / ARMovie)
871 "rsd", // rsd (GameCube RSD)
872 "rso", // rso (Lego Mindstorms RSO)
873 "rtp", // rtp (RTP input)
874 "rtsp", // rtsp (RTSP input)
875 "smi", "sami", // sami (SAMI subtitle format)
876 "sap", // sap (SAP input)
877 "sbg", // sbg (SBaGen binaural beats script)
878 "sdp", // sdp (SDP)
879 // "sdr2", // sdr2 (SDR2)
880 "film_cpk", // film_cpk (Sega FILM / CPK)
881 "shn", // shn (raw Shorten)
882 // "vb,son", // siff (Beam Software SIFF)
883 // "sln", // sln (Asterisk raw pcm)
884 "smk", // smk (Smacker)
885 // "mjpg", // smjpeg (Loki SDL MJPEG)
886 "smush", // smush (LucasArts Smush)
887 "sol", // sol (Sierra SOL)
888 "sox", // sox (SoX native)
889 "spdif", // spdif (IEC 61937 (compressed data in S/PDIF))
890 "srt", // srt (SubRip subtitle)
891 "psxstr", // psxstr (Sony Playstation STR)
892 "stl", // stl (Spruce subtitle format)
893 "sub", "subviewer1", // subviewer1 (SubViewer v1 subtitle format)
894 "sub", "subviewer", // subviewer (SubViewer subtitle format)
895 "sup", // sup (raw HDMV Presentation Graphic Stream subtitles)
896 // "swf", // swf (SWF (ShockWave Flash))
897 "tak", // tak (raw TAK)
898 "tedcaptions", // tedcaptions (TED Talks captions)
899 "thp", // thp (THP)
900 "tiertexseq", // tiertexseq (Tiertex Limited SEQ)
901 "tmv", // tmv (8088flex TMV)
902 "thd", "truehd", // truehd (raw TrueHD)
903 "tta", // tta (TTA (True Audio))
904 // "txd", // txd (Renderware TeXture Dictionary)
905 "ans", "art", "asc", "diz", "ice", "nfo", "txt", "vt", // tty (Tele-typewriter)
906 // "vc1", // vc1 (raw VC-1)
907 "vc1test", // vc1test (VC-1 test bitstream)
908 // "viv", // vivo (Vivo)
909 "vmd", // vmd (Sierra VMD)
910 "idx", "vobsub", // vobsub (VobSub subtitle format)
911 "voc", // voc (Creative Voice)
912 "txt", "vplayer", // vplayer (VPlayer subtitles)
913 "vqf", "vql", "vqe", // vqf (Nippon Telegraph and Telephone Corporation (NTT) TwinVQ)
914 "w64", // w64 (Sony Wave64)
915 "wav", // wav (WAV / WAVE (Waveform Audio))
916 "wc3movie", // wc3movie (Wing Commander III movie)
917 "webm_dash_manifest", // webm_dash_manifest (WebM DASH Manifest)
918 "vtt", "webvtt", // webvtt (WebVTT subtitle)
919 "wsaud", // wsaud (Westwood Studios audio)
920 "wsvqa", // wsvqa (Westwood Studios VQA)
921 "wtv", // wtv (Windows Television (WTV))
922 "wv", // wv (WavPack)
923 "xa", // xa (Maxis XA)
924 "xbin", // xbin (eXtended BINary text (XBIN))
925 "xmv", // xmv (Microsoft XMV)
926 "xwma", // xwma (Microsoft xWMA)
927 // "yop", // yop (Psygnosis YOP)
928 // "y4m", // yuv4mpegpipe (YUV4MPEG pipe)
929 "bmp_pipe", // bmp_pipe (piped bmp sequence)
930 "dds_pipe", // dds_pipe (piped dds sequence)
931 "dpx_pipe", // dpx_pipe (piped dpx sequence)
932 "exr_pipe", // exr_pipe (piped exr sequence)
933 "j2k_pipe", // j2k_pipe (piped j2k sequence)
934 "jpeg_pipe", // jpeg_pipe (piped jpeg sequence)
935 "jpegls_pipe", // jpegls_pipe (piped jpegls sequence)
936 "pictor_pipe", // pictor_pipe (piped pictor sequence)
937 "png_pipe", // png_pipe (piped png sequence)
938 "qdraw_pipe", // qdraw_pipe (piped qdraw sequence)
939 "sgi_pipe", // sgi_pipe (piped sgi sequence)
940 "sunrast_pipe", // sunrast_pipe (piped sunrast sequence)
941 "tiff_pipe", // tiff_pipe (piped tiff sequence)
942 "webp_pipe", // webp_pipe (piped webp sequence)
943
944 // OIIO and PFM extensions:
945 "bmp", "cin", "dds", "dpx", "f3d", "fits", "hdr", "ico",
946 "iff", "jpg", "jpe", "jpeg", "jif", "jfif", "jfi", "jp2", "j2k", "exr", "png",
947 "pbm", "pgm", "ppm",
948 "pfm",
949 "psd", "pdd", "psb", "ptex", "rla", "sgi", "rgb", "rgba", "bw", "int", "inta", "pic", "tga", "tpic", "tif", "tiff", "tx", "env", "sm", "vsm", "zfile",
950
951 NULL
952 };
953 for (const char*const* e = extensions_blacklist; *e != NULL; ++e) {
954 extensionsl.remove(*e);
955 }
956
957 _extensions.assign( extensionsl.begin(), extensionsl.end() );
958 // sort / unique
959 std::sort( _extensions.begin(), _extensions.end() );
960 _extensions.erase( std::unique( _extensions.begin(), _extensions.end() ), _extensions.end() );
961 #endif // if 0
962 } // ReadFFmpegPluginFactory::load
963
964 /** @brief The basic describe function, passed a plugin descriptor */
965 void
describe(ImageEffectDescriptor & desc)966 ReadFFmpegPluginFactory::describe(ImageEffectDescriptor &desc)
967 {
968 GenericReaderDescribe(desc, _extensions, kPluginEvaluation, kSupportsTiles, false);
969 // basic labels
970 desc.setLabel(kPluginName);
971 desc.setPluginDescription(kPluginDescription);
972 #ifdef OFX_IO_MT_FFMPEG
973 // Register a lock manager callback with FFmpeg, providing it the ability to use mutex locking around
974 // otherwise non-thread-safe calls.
975 av_lockmgr_register(FFmpegLockManager);
976 desc.setRenderThreadSafety(eRenderFullySafe);
977 #else
978 desc.setRenderThreadSafety(eRenderInstanceSafe);
979 #endif
980
981 av_log_set_level(AV_LOG_WARNING);
982 avcodec_register_all();
983 av_register_all();
984
985 _manager.reset(new FFmpegFileManager);
986 _manager->init();
987
988 // Thus effect prefers sequential render, but will still give correct results otherwise
989 desc.getPropertySet().propSetInt(kOfxImageEffectInstancePropSequentialRender, 2, false);
990 }
991
992 /** @brief The describe in context function, passed a plugin descriptor and a context */
993 void
describeInContext(ImageEffectDescriptor & desc,ContextEnum context)994 ReadFFmpegPluginFactory::describeInContext(ImageEffectDescriptor &desc,
995 ContextEnum context)
996 {
997 // make some pages and to things in
998 PageParamDescriptor *page = GenericReaderDescribeInContextBegin(desc, context, isVideoStreamPlugin(),
999 kSupportsRGBA, kSupportsRGB, kSupportsXY, kSupportsAlpha, kSupportsTiles, false);
1000
1001 {
1002 IntParamDescriptor *param = desc.defineIntParam(kParamMaxRetries);
1003 param->setLabel(kParamMaxRetriesLabel);
1004 param->setHint(kParamMaxRetriesHint);
1005 param->setAnimates(false);
1006 param->setDefault(10);
1007 param->setRange(0, 100);
1008 param->setDisplayRange(0, 20);
1009 if (page) {
1010 page->addChild(*param);
1011 }
1012 }
1013 {
1014 BooleanParamDescriptor *param = desc.defineBooleanParam(kParamFirstTrackOnly);
1015 param->setLabelAndHint(kParamFirstTrackOnlyLabelAndHint);
1016 param->setAnimates(false);
1017 param->setDefault(false);
1018 param->setLayoutHint(eLayoutHintDivider);
1019 if (page) {
1020 page->addChild(*param);
1021 }
1022 }
1023 {
1024 PushButtonParamDescriptor* param = desc.definePushButtonParam(kParamLibraryInfo);
1025 param->setLabelAndHint(kParamLibraryInfoLabel);
1026 if (page) {
1027 page->addChild(*param);
1028 }
1029 }
1030
1031 GenericReaderDescribeInContextEnd(desc, context, page, "rec709", "scene_linear");
1032 }
1033
1034 /** @brief The create instance function, the plugin must return an object derived from the \ref ImageEffect class */
1035 ImageEffect*
createInstance(OfxImageEffectHandle handle,ContextEnum)1036 ReadFFmpegPluginFactory::createInstance(OfxImageEffectHandle handle,
1037 ContextEnum /*context*/)
1038 {
1039 ReadFFmpegPlugin* ret = new ReadFFmpegPlugin(*_manager, handle, _extensions);
1040
1041 ret->restoreStateFromParams();
1042
1043 return ret;
1044 }
1045
1046 static ReadFFmpegPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
1047 mRegisterPluginFactoryInstance(p)
1048
1049 OFXS_NAMESPACE_ANONYMOUS_EXIT
1050