jeudi 26 février 2015

Write an encoded video to the memory with Microsoft Media Foundation


I'm writing a code which exports the encoded video for live streaming with Microsoft Media Foundation and C++(Visual Stuido 2013 on Windows 8.1 64bit).


I succeeded in creating mp4 file from multiple images. I would like to output the data for every frame to the memory instead of a file. However, this code cannot get the correct result(That is not live streaming format in order that a seeking position moves to the front?).


If it has the way or information which output data of one frame to the memory, please let me know.



bool Encode::first = true;

Encode::Encode()
{
}

Encode::~Encode()
{
Uninitalize();
}

void Encode::Uninitalize()
{
Close();
}

bool Encode::Initialize(int width, int height, int bitrate)
{
if (first == true){
first = false;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
MFStartup(MF_VERSION);
}

w = width;
h = height;

HRESULT hr;

IMFAttributes *spattr = NULL;
BYTE *framebuf = new BYTE[bitrate * 1024];
memstream = SHCreateMemStream(framebuf, bitrate * 1024);
hr = MFCreateMFByteStreamOnStreamEx(memstream, &outstream);
delete[]framebuf;
if (FAILED(hr)) return false;

MFCreateAttributes(&spattr, 10);
spattr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
spattr->SetUINT32(MF_LOW_LATENCY, TRUE);

hr = MFCreateSinkWriterFromURL(L".mp4", outstream, spattr, &writer);
RELEASE(spattr);
if (FAILED(hr)) return false;

IMFMediaType *mediaout;
MFCreateMediaType(&mediaout);
mediaout->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
mediaout->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
mediaout->SetUINT32(MF_MT_AVG_BITRATE, bitrate * 1024);
mediaout->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
MFSetAttributeSize(mediaout, MF_MT_FRAME_SIZE, width, height);
MFSetAttributeRatio(mediaout, MF_MT_FRAME_RATE, 60, 1);
MFSetAttributeRatio(mediaout, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);

hr = writer->AddStream(mediaout, &sindex);
if (FAILED(hr)) goto EXIT;

IMFMediaType *mediain;
MFCreateMediaType(&mediain);
mediain->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
mediain->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32);
mediain->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
MFSetAttributeSize(mediain, MF_MT_FRAME_SIZE, width, height);
MFSetAttributeRatio(mediain, MF_MT_FRAME_RATE, 60, 1);
MFSetAttributeRatio(mediain, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);

hr = writer->SetInputMediaType(sindex, mediain, NULL);
if (FAILED(hr)) goto EXIT;

hr = writer->BeginWriting();

EXIT:
RELEASE(mediaout);
RELEASE(mediain);

return SUCCEEDED(hr);
}

void Encode::WriteFrame(BYTE *bits)
{
int stride = w * 4;
int buflen = h * w * 4;

HRESULT hr;
IMFMediaBuffer *buffer;
MFCreateMemoryBuffer(buflen, &buffer);

BYTE *p;
buffer->Lock(&p, NULL, NULL);
MFCopyImage(p, stride, bits, stride, stride, h);
buffer->Unlock();
buffer->SetCurrentLength(buflen);

IMFSample *sample;
MFCreateSample(&sample);
sample->AddBuffer(buffer);

hr = writer->WriteSample(sindex, sample);

RELEASE(sample);
RELEASE(buffer);
}

int Encode::ReadEncodedFrame(BYTE *buf, int buflen)
{
ULONG read = 0;
QWORD pos;
outstream->GetCurrentPosition(&pos);
if (pos > 0){
outstream->SetCurrentPosition(0);
outstream->Read(buf, pos, &read);
outstream->SetCurrentPosition(0);
}
return (int)read;
}

void Encode::Flush()
{
if (writer) writer->Finalize();
}

void Encode::Close()
{
RELEASE(memstream);

RELEASE(writer);

if (outstream){
outstream->Close();
RELEASE(outstream);
}
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
FILE *fp = fopen("C:\\data\\0.mp4", "wb");

Encode en;
en.Initialize(640,480,512);
int buflen = 640 * 480 * 4;
BYTE *buf = new BYTE[buflen];
for (int i = 0; i < 256; i++){
memset(buf, i, buflen);
en.WriteFrame(buf);

int read = en.ReadEncodedFrame(buf, buflen);
if(read > 0) fwrite(buf, read, 1, fp);
}
en.Flush();

int read = en.ReadEncodedFrame(buf, buflen);
if (read > 0) fwrite(buf, read, 1, fp);

fclose(fp);

en.Close();

return 0;
}



Aucun commentaire:

Enregistrer un commentaire