Код: Выделить всё
sample.mp4
Проблема:
Временная метка вместо того, чтобы начинаться с 0, начинается с 0,333 (очевидно это значение продолжительности кадра). Я не могу понять, в чем причина этого.
Код: Выделить всё
#define MFWRITER_RETURN_ON_ERROR(A) if( !(A) ) { return false; }
#define MFWRITER_RETURN_HRESULT_ON_ERROR(A) if( FAILED(A) ) {return A; }
const double HUNDRED_NANOSECONDS = 10000000.0;
class MFInitializer
{
public:
MFInitializer()
: _hrCOM(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))
{
_hrMF = MFStartup(MF_VERSION);
}
~MFInitializer()
{
if (SUCCEEDED(_hrMF))
{
MFShutdown();
}
if (SUCCEEDED(_hrCOM))
{
CoUninitialize();
}
}
private:
HRESULT _hrCOM; ///< result of COM initialization
HRESULT _hrMF; ///< result of Media Foundation Initialization
};
class MFWriter {
public:
MFWriter();
~MFWriter();
void init();
void open();
void close();
void term();
const unsigned char* readbinfile(std::string frame);
bool write(const unsigned char* input);
HRESULT createSinkWriter(UINT32 width, UINT32 height);
void destroySinkWriter();
bool throwIf(HRESULT hr);
CComPtr createMediaBuffer(const unsigned char* const input);
uint32_t computeH264BitRate(const uint32_t quality, uint32_t width, uint32_t height,
double frameRate, size_t bitsPerPixel);
static const char* const FILE_NAME;
static const char* const FRAME_RATE;
static const char* const QUALITY;
static const char* const EXPECTED_FRAME_TYPE;
static const size_t MAX_QUALITY;
static const double INVALID_QUALITY;
static const std::string FRAME_TYPE_FOR_MPEG4;
std::unique_ptr _mfInit;
CComPtr _sinkWriter;
DWORD _videoStreamIndex;
double _frameRate;
UINT32 _quality;
bool _fileSpaceAvailable;
LONGLONG _frameStart;
UINT64 _frameDuration;
};
MFWriter::MFWriter() :
_mfInit(),
_sinkWriter(NULL),
_videoStreamIndex(0),
_frameRate(0),
_quality(0),
_fileSpaceAvailable(true),
_frameStart(0),
_frameDuration(0)
{
}
void MFWriter::init() {
_mfInit.reset(new MFInitializer());
}
void MFWriter::open()
{
_frameRate = 30;
_quality = 75;
_fileSpaceAvailable = true;
}
bool MFWriter::throwIf(HRESULT hr)
{
//prints error and calls exit()
}
bool MFWriter::write(const unsigned char* const input)
{
const size_t width = 320;
const size_t height = 240;
const size_t channels = 3;
if (_sinkWriter == NULL)
{
HRESULT hr = createSinkWriter(static_cast(width), static_cast(height));
// If any failure occurs after the SyncWriter is created, we need to clean it up
// as the device is not closed.
if (FAILED(hr))
{
destroySinkWriter();
return throwIf(hr);
}
}
CComPtr mediaBuffer(createMediaBuffer(input));
MFWRITER_RETURN_ON_ERROR(throwIf(mediaBuffer == NULL ? E_UNEXPECTED : S_OK));
// Create a media sample and add the buffer to the sample.
CComPtr sample;
MFWRITER_RETURN_ON_ERROR(throwIf(MFCreateSample(&sample)));
MFWRITER_RETURN_ON_ERROR(throwIf(sample->AddBuffer(mediaBuffer)));
// Set the time stamp and the duration.
MFWRITER_RETURN_ON_ERROR(throwIf(sample->SetSampleTime(_frameStart)));
MFWRITER_RETURN_ON_ERROR(throwIf(sample->SetSampleDuration(_frameDuration)));
// Send the sample to the Sink Writer.
MFWRITER_RETURN_ON_ERROR(throwIf(_sinkWriter->WriteSample(_videoStreamIndex, sample)));
_frameStart += _frameDuration;
return true;
}
HRESULT MFWriter::createSinkWriter(UINT32 width, UINT32 height)
{
CComPtr pMediaTypeOut;
CComPtr pMediaTypeIn;
std::wstring wideFile = L"sample.mp4";
MFWRITER_RETURN_HRESULT_ON_ERROR(MFCreateSinkWriterFromURL(wideFile.c_str(), NULL, NULL, &_sinkWriter));
// Set the output media type.
MFWRITER_RETURN_HRESULT_ON_ERROR(MFCreateMediaType(&pMediaTypeOut));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeOut->SetUINT32(MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Main));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, computeH264BitRate(_quality, width, height, _frameRate, 24)));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
MFWRITER_RETURN_HRESULT_ON_ERROR(MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, width, height));
_frameDuration = static_cast(std::round((1.0 / _frameRate) * HUNDRED_NANOSECONDS));
// Derive the frame rate from
UINT32 rateNumerator = 0, rateDenominator = 0;
MFWRITER_RETURN_HRESULT_ON_ERROR(MFAverageTimePerFrameToFrameRate(_frameDuration, &rateNumerator, &rateDenominator));
MFWRITER_RETURN_HRESULT_ON_ERROR(MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, rateNumerator, rateDenominator));
MFWRITER_RETURN_HRESULT_ON_ERROR(MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 1, 1));
MFWRITER_RETURN_HRESULT_ON_ERROR(_sinkWriter->AddStream(pMediaTypeOut, &_videoStreamIndex));
// Set the input media type.
MFWRITER_RETURN_HRESULT_ON_ERROR(MFCreateMediaType(&pMediaTypeIn));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2));
MFWRITER_RETURN_HRESULT_ON_ERROR(pMediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
MFWRITER_RETURN_HRESULT_ON_ERROR(MFSetAttributeSize(pMediaTypeIn, MF_MT_FRAME_SIZE, width, height));
MFWRITER_RETURN_HRESULT_ON_ERROR(MFSetAttributeRatio(pMediaTypeIn, MF_MT_FRAME_RATE, rateNumerator, rateDenominator));
MFWRITER_RETURN_HRESULT_ON_ERROR(MFSetAttributeRatio(pMediaTypeIn, MF_MT_PIXEL_ASPECT_RATIO, 1, 1));
MFWRITER_RETURN_HRESULT_ON_ERROR(_sinkWriter->SetInputMediaType(_videoStreamIndex, pMediaTypeIn, NULL));
_frameStart = 0;
// Tell the sink writer to start accepting data.
MFWRITER_RETURN_HRESULT_ON_ERROR(_sinkWriter->BeginWriting());
return true;
}
CComPtr MFWriter::createMediaBuffer(const unsigned char* const input)
{
const size_t width = 320;
const size_t height = 240;
const size_t channels = 3;
// Create a new memory buffer.
CComPtr outputBuffer;
size_t totalBytesInBuffer = height * width * channels * 1;
HRESULT hr = MFCreateMemoryBuffer(static_cast(totalBytesInBuffer), &outputBuffer);
if (FAILED(hr))
{
return NULL;
}
BYTE* outputData = NULL;
hr = outputBuffer->Lock(&outputData, NULL, NULL);
if (FAILED(hr))
{
return NULL;
}
// Copy input data to the Media Sample
// As the input buffer contains data in YUY2 format, the effective width of the frame is doubled.
const LONG bytesPerRow = static_cast(2.0 * width);
hr = MFCopyImage(outputData, // Destination buffer.
bytesPerRow, // Destination stride (bytes per row).
reinterpret_cast(input), // First row in source image.
bytesPerRow, // Source stride.
bytesPerRow, // Image width in bytes.
static_cast(height)); // Image height in pixels.
if (FAILED(hr))
{
return NULL;
}
outputBuffer->Unlock();
// Set the data length of the buffer after writing.
hr = outputBuffer->SetCurrentLength(static_cast(totalBytesInBuffer));
if (FAILED(hr))
{
return NULL;
}
return outputBuffer;
}
int main() {
MFWriter* _mfwrite = new MFWriter();
std::cout
Подробнее здесь: [url]https://stackoverflow.com/questions/79172804/mediafoundation-timestamp-of-first-frame-is-not-getting-correctly-set-to-0-ins[/url]