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