Is there a VideoWriter for Windows?

Hi all,

I’m trying to record video to disk using a webcam. It seems like an incredibly easy thing to do on OSX using QuickTime’s videowriter, but I can’t find the equivalent for windows…

I need to record the video in real-time and initiate an upload to a cloud server as soon as soon as the file writes to disk. As such, saving frames as PNGs or using Fraps isn’t an option for me.

I’ve tried using OpenCV’s cv::VideoWriter, but it throws errors as soon as I attempt to instantiate it. Example below:

cv::VideoWriter mVideoWriter;

std::string filename = "test";

mVideoWriter = cv::VideoWriter(filename, CV_FOURCC_MACRO('P', 'I', 'M', '1'), 30, cv::Size(1280,720), true);

but it throws the follows errors:
1>VideoWriterTestApp.obj : error LNK2019: unresolved external symbol “public: __thiscall cv::VideoWriter::VideoWriter(void)” (??0VideoWriter@cv@@QAE@XZ) referenced in function “public: __thiscall VideoWriterTestApp::VideoWriterTestApp(void)” (??0VideoWriterTestApp@@QAE@XZ)
1>VideoWriterTestApp.obj : error LNK2019: unresolved external symbol “public: virtual __thiscall cv::VideoWriter::~VideoWriter(void)” (??1VideoWriter@cv@@UAE@XZ) referenced in function “public: virtual __thiscall VideoWriterTestApp::~VideoWriterTestApp(void)” (??1VideoWriterTestApp@@UAE@XZ)

Is VideoWriter excluded from Cinder’s implementation?

Any help would be greatly appreciated! Thanks!

ci::qtime::MovieWriter is cross platform as far as I know.

Looks like you have missed linking opencv_videoio library.

Bala.

Thanks @balachandran_c, it didn’t occur to me that the block wouldn’t link to all the libraries.

I’ve tried adding it manually, but get a new linker error:

1>LINK : fatal error LNK1104: cannot open file '..\blocks\OpenCV3\lib\vc2013\x86\opencv_videoio300d.lib'

The lib definitely exists and is definitely in the correct location, and the filename is definitely correct ( i did plenty of copy/pasting to ensure filenames and locations were correct ). See below:

..\blocks\OpenCV3\lib\vc2013\x86\opencv_video300d.lib
..\blocks\OpenCV3\lib\vc2013\x86\opencv_videostab300d.lib
..\blocks\OpenCV3\lib\vc2013\x86\ippicvmt.lib
..\blocks\OpenCV3\lib\vc2013\x86\opencv_videoio300d.lib

Any ideas?

@lithium I had read that somewhere as well, but doesn’t seem to work for me. Trying to build a basic example in VS2013, toolchain v120, I get the following errors:

1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(150): error C2143: syntax error: missing ';' before '*'
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(150): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(150): error C2238: unexpected token(s) preceding ';'
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(151): error C2143: syntax error: missing ';' before '*'
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(151): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(151): error C2238: unexpected token(s) preceding ';'
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(152): error C2143: syntax error: missing ';' before '*'
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(152): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\desktop\cinder\include\cinder\qtime\avfwriter.h(152): error C2238: unexpected token(s) preceding ';'

If I look inside AvfWriter.h, I see that the following three identifiers are undefined:

	AVAssetWriter*							mWriter;
	AVAssetWriterInput*						mWriterSink;
	AVAssetWriterInputPixelBufferAdaptor*	mSinkAdapater;

Which i assume is because of the following:

#if defined( CINDER_MAC ) || defined( CINDER_COCOA_TOUCH )
	#include "cinder/cocoa/CinderCocoa.h"
	#include <CoreVideo/CoreVideo.h>

	#if defined( __OBJC__ )
		@class AVAsset, AVAssetWriter, AVAssetWriterInput, AVAssetWriterInputPixelBufferAdaptor, NSDate;
	#else
		class AVAsset;
		class AVAssetWriter;
		class AVAssetWriterInput;
		class AVAssetWriterInputPixelBufferAdaptor;
	#endif
#endif

I’m not too experienced, but from what I understand this means that because it’s not an application for OSX, it’s not designed to be used this way?

Thanks!

In windows this has worked for me.

Look at the example:
cinder-master\samples\QuickTimeAvfWriter
Use
#include "cinder/qtime/MovieWriter.h"
instead of
#include "cinder/qtime/AvfWriter.h"

Now you can write movies in Windows,ONLY in 32 bits.

AVFWriter is the mac (AVFoundation) implementation of the MovieWriter interface. Looking at the source it seems MovieWriter its only implemented on 32-bit windows. You’ll need to include "cinder/qtime/MovieWriter.h" and link against the QuickTime libraries that ship with cinder in the blocks/QuickTime folder

It looks like you have given the path of the library along with its filename. To simplify things, it would be better to just give the name of the library opencv_videoio300d.lib in the Linker > Input > Additional Dependencies section, and the path to the library in Linker > General > Additional Library Directories section. Additionally, check the command line that is issued by the linker ( in Linker > Command Line section ), to see whether it matches what you believe to be happening.

1 Like

@lithium apologies for the delay in responding, I’ve only just had time to come back to this. I tried your advice, and also followed the guide here from Cinder’s Notes.

I created a project using Tinderbox and included the QuickTime block. I’m using Visual Studio 2013 with the 0.9.0 Release of Cinder. The code is as follows:

#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/qtime/MovieWriter.h"
#include "cinder/Utilities.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class MovieWriterTestApp : public App {
  public:
	void setup() override;
	void mouseDown( MouseEvent event ) override;
	void update() override;
	void draw() override;

	qtime::MovieWriterRef mMovie;
};

void MovieWriterTestApp::setup()
{
	fs::path path = getSaveFilePath();
	if (!path.empty()) {
		auto format = qtime::MovieWriter::Format();
		format.setCodec(qtime::MovieWriter::CODEC_JPEG);
		mMovie = qtime::MovieWriter::create(path, getWindowWidth(), getWindowHeight(), format);
	}
	
}

Here’s the error that appears:

And the final line of the stack trace points to this err (line 222 of MovieWriter.cpp)

 // Create a movie for this file (data ref)
    	err = ::CreateMovieStorage( dataRef, dataRefType, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &mDataHandler, &mMovie );
    	::DisposeHandle( dataRef );
        if( err )
            throw MovieWriterExc();

Hey mate. I had a quick play around and saw the same behaviour on my new windows dev box, but couldn’t replicate it on my old windows dev box. This reminded me that there used to be a note in the QuickTime setup in an earlier version of cinder that required you to download and install QuickTime from http://apple.com/quicktime/download before any of the video stuff would work. Since QuickTime is all but deprecated in cinder (i believe 32-bit windows is all that supports it), that part of the documentation seems to have gone by the wayside.

Once i installed quicktime and restarted (one of the few times it actually seems to be necessary), your code worked as expected.

Hope that helps,

A.

Dude, you’re a champ, that worked a treat! With the benefit of hindsight, it’s totally logical that you’d need to install quicktime on windows in order to use quicktime!!!

I’m just taken a back that there’s not an easier / more elegant way to write a video to disk on windows. I would’ve thought it would be something people needed to do on occasion, I can’t find a single other solution for how anyone’s used Cinder to do it on Windows!

Thanks again!

No worries. My only guess for the second bit is the wide range of screen recording software available for windows that isn’t an option on other platforms. Some cards even seem to have driver level screen capture so my guess is people just use that, or things like fraps.

I guess the main reason there is no great video solution (either writing or playing) on Windows, is that all native and hardware accelerated video solutions are only available for DirectX, not for OpenGL. You have to be proficient in both backends to come up with a solid solution. Even then, sharing textures between OpenGL and DirectX causes additional problems. Here’s to hoping that NVIDIA and AMD will add OpenGL access to their hardware encoder/decoder on Windows.

FYI: QuickTime on Windows is not hardware accelerated. It’s also notoriously slow compared to native video solutions.

So, I needed a better way to write video in Windows. After looking different options, all of them seemed like a nightmare to implement. Then I got lucky and found Tutorial: Using the Sink Writer to Encode Video

It has worked well for now, so I made a block trying to keep the same structure as the qtime::MovieWriter:

I know its very hacky, so any thoughts on how to make it a proper tool would be appreciated.

2 Likes

Thanks! I’ll fork it and take a look!

Thanks @xumo! Going to try it out as well!

I want to notify anyone looking at the cv::VideoWriter option that it does produce great quality (with the MSMF backend), but that quality gets wrecked when you upload the result to YouTube. For whatever reason. :slight_smile: