PDA

View Full Version : C++ file writing (plugin development)


patrick_
11th November 2008, 15:39
I don't have any experience with C++ (I normally use C#), but am trying to write a plugin.

This is my code:

#include "windows.h"
#include "avisynth.h"
#include <fstream>
using namespace std;

class SaveRAW : public GenericVideoFilter {
public:
SaveRAW(PClip _child, const char* _filename, IScriptEnvironment* env);
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
~SaveRAW();
private:
int framesize;
fstream file;
};

SaveRAW::SaveRAW(PClip _child, const char* _filename, IScriptEnvironment* env) : GenericVideoFilter(_child) {
framesize = vi.width * vi.height * vi.BitsPerPixel() / 8;
fstream file(_filename, ios::binary | ios::out);
if (!file) env->ThrowError("could not create file");
}

SaveRAW::~SaveRAW() {
file.close();
}

PVideoFrame __stdcall SaveRAW::GetFrame(int n, IScriptEnvironment* env) {
PVideoFrame src = child->GetFrame(n, env);
const unsigned char* srcp = src->GetReadPtr();
file.write((const char*)srcp, framesize);
return src;
}

AVSValue __cdecl Create_SaveRAW(AVSValue args, void* user_data, IScriptEnvironment* env) {
return new SaveRAW(args[0].AsClip(), args[1].AsString(), env);
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("SaveRAW", "cs", Create_SaveRAW, 0);
return "`SaveRAW' SaveRAW plugin";
}


I'm trying to write the RAW video data (will be in YV12) to a file. The code creates the file, but for some reason doesn't write any data.

I guess I'm just making some stupid mistake, but I don't really have a clue about what it can be.

BTW I took part of this code from another filter, and this:
const unsigned char* srcp = src->GetReadPtr();
file.write((const char*)srcp, framesize);
seems a little strange to me: casting an unsigned char to a char, especially considering that GetReadPtr returns a byte.

Thanks in advance for any help.

neuron2
11th November 2008, 17:21
Basic question but I have to ask: Are you playing the script in a player to ensure that GetFrame() is actually called?

If you set a breakpoint on GetFrame() and trace, do you see correct data and framesize?

patrick_
11th November 2008, 18:42
I was using MPC to play the video.


I've tried to replace the fstream class with
constructor
_sopen_s(&fileHandle, _filename, _O_RDWR | _O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE)
Getframe
_write( fileHandle, (const char*)srcp, framesize);
Destructor
_close( fileHandle );

Using AVS2AVI when debugging, everything works fine with this code - output seems to be the same as the AVS2AVI generated AVI (except for the frame headers of course).
Still, I don't understand why the fstream class doesn't work in my code :(

neuron2
11th November 2008, 19:18
Your usage of the fstream class looks very weird to me. I am used to seeing things like this:

std::ofstream outFile;
outFile.open( "output.bin", ios::out | ios::binary );
outFile.write( buffer, 20 );
outFile.close(); Even if your syntax is valid, don't you have two instances of file? The one you open in SaveRAW() is lost when the scope is exited and not the same one you write to in GetFrame(). I'll bet your write returns an error. You're not checking it.

patrick_
11th November 2008, 19:44
I changed my declaration and constructor for your syntax:
std::ofstream outFile;
outFile.open( "output.bin", ios::out | ios::binary );

and now it does work, but about having two instances:

the outFile is Private, so it can be accessed from within any part of the class (and I just read that in C++ friends can access as well) and will always point to the same instance.

so if you use:

Class declaration:
private:
std::ofstream outFile;
Constructor:
outFile.open(_filename, ios::binary | ios::out);
GetFrame:
outFile.write((const char*)srcp,framesize);
Destructor:
outFile.close();

There's only one instance of outFile. Actually that's the point of using constructors and destructors. If you'ld have to declare a new outFile everytime you enter the GetFrame function, and so have to open/close everytime the file - which implies forcing the OS the flush to disk, that would involve a lot of overhead (note that Vista caches about 32MB of filedata before writing to the harddisk if you don't flush and have suficient RAM available).

If you want, I can send you the source, so you can see I'm right that there's only one instance (just check the filehandle).

Gavino
11th November 2008, 19:57
... you can see I'm right that there's only one instance (just check the filehandle).
There is now that you've changed it! But your original version had two, the extra one being a local variable in the constructor.

patrick_
11th November 2008, 20:46
OK, I didn't know that. I thought "fstream file" is the like in C# "file = new fstream" - that's just because the MSDN Library explains really bad.

neuron2
11th November 2008, 20:50
I thought "fstream file" is the like in C# "file = new fstream" It is, but then the object is automatically free'ed when you leave its scope, i.e., the function. And even if it wasn't free'ed, it wouldn't refer to the same object in the class definition.

patrick_
11th November 2008, 20:57
Thanks for explaining. So it's actually more like C# "fstream file = new fstream". If you would do that in C# at least you get a warning telling that you're hiding the private variable file.

neuron2
11th November 2008, 21:00
I thought we were writing C++ code. :)

Leak
11th November 2008, 21:35
OK, I didn't know that. I thought "fstream file" is the like in C# "file = new fstream" - that's just because the MSDN Library explains really bad.
I guess the following should have worked:

SaveRAW::SaveRAW(PClip _child, const char* _filename, IScriptEnvironment* env)
: GenericVideoFilter(_child),
file(_filename, ios::binary | ios::out)
{
framesize = vi.width * vi.height * vi.BitsPerPixel() / 8;
if (!file) env->ThrowError("could not create file");
}

That would have called the constructor for your "file" member variable with "_filename" and "ios::binary | ios::out" as parameters - before beginning execution of your constructor code itself.

np: The Orb - O.O.B.E (John Peel - 12.05.95) (The BBC Sessions (Disc 1))