Anonymous
Media Foundation: TimeStamp первого кадра неправильно устанавливается на 0. Вместо этого ему присваивается значение 0,33
Сообщение
Anonymous » 09 ноя 2024, 15:51
Я пытаюсь прочитать два кадра (по отдельности хранящиеся в двоичных файлахframe1.bin иframe2.bin) и создать видеофайл mp4 с именем «sample.mp4». Временная метка начинается с 0,0333 (по-видимому, это значение длительности кадра), а не с 0. Я не могу найти причину этого.
Код: Выделить всё
#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-frst-frame-is-not-getting-correctly-set-to-0-inst[/url]
1731156700
Anonymous
Я пытаюсь прочитать два кадра (по отдельности хранящиеся в двоичных файлахframe1.bin иframe2.bin) и создать видеофайл mp4 с именем «sample.mp4». Временная метка начинается с 0,0333 (по-видимому, это значение длительности кадра), а не с 0. Я не могу найти причину этого. [code] #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-frst-frame-is-not-getting-correctly-set-to-0-inst[/url]