Created
June 29, 2022 08:56
-
-
Save falsycat/5ded0a92625b6f38c7f871dddb638158 to your computer and use it in GitHub Desktop.
create mp4 video using minimp4.h + openh264
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cassert> | |
#include <cstdint> | |
#include <cstring> | |
#include <iostream> | |
#define MINIMP4_IMPLEMENTATION | |
#include "minimp4.h" | |
#include "../codec/api/wels/codec_api.h" | |
int write_cb(int64_t off, const void* buf, size_t size, void* ptr) { | |
FILE* fp = (FILE*) ptr; | |
fseek(fp, off, SEEK_SET); | |
return fwrite(buf, 1, size, fp) != size; | |
} | |
int main(void) { | |
ISVCEncoder* enc; | |
if (WelsCreateSVCEncoder(&enc)) assert(false); | |
assert(enc); | |
// muxer init | |
constexpr int w = 16, h = 16, fps = 30; | |
FILE* fout = fopen("hello.mp4", "wb"); | |
FILE* fraw = fopen("hello.h264", "wb"); | |
assert(fout); | |
assert(fraw); | |
MP4E_mux_t* mux = MP4E_open(false, false, fout, write_cb); | |
mp4_h26x_writer_t writer; | |
if (MP4E_STATUS_OK != mp4_h26x_write_init(&writer, mux, w, h, false)) { | |
assert(false && "failed to init mp4_h26x_writer_t"); | |
} | |
// encoder proc | |
SEncParamBase p = {}; | |
p.iUsageType = SCREEN_CONTENT_REAL_TIME; | |
p.fMaxFrameRate = 30; | |
p.iPicWidth = w; | |
p.iPicHeight = h; | |
p.iTargetBitrate = 5000000; | |
enc->Initialize(&p); | |
int level = WELS_LOG_INFO; | |
enc->SetOption(ENCODER_OPTION_TRACE_LEVEL, &level); | |
int fmt = videoFormatI420; | |
enc->SetOption(ENCODER_OPTION_DATAFORMAT, &fmt); | |
int framesz = w*h*3/2; | |
SFrameBSInfo info = {}; | |
SSourcePicture pic = {}; | |
pic.iPicWidth = w; | |
pic.iPicHeight = h; | |
pic.iColorFormat = videoFormatI420; | |
pic.iStride[0] = pic.iPicWidth; | |
pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1; | |
uint8_t buf[framesz]; | |
pic.pData[0] = buf; | |
pic.pData[1] = pic.pData[0] + w*h; | |
pic.pData[2] = pic.pData[1] + (w*h >> 2); | |
for (int i = 0; i < 300; ++i) { | |
std::cout << "frame#" << i << std::endl; | |
std::memset(buf, 0, framesz); | |
for (int y = 0; y < h; ++y) { | |
for (int x = 0; x < w; ++x) { | |
const double lum = static_cast<double>(x*y)/static_cast<double>(w*h); | |
buf[y*w+x] = static_cast<uint8_t>(lum*256); | |
} | |
} | |
// encode it | |
if (enc->EncodeFrame(&pic, &info) != cmResultSuccess) assert(false); | |
if (info.eFrameType != videoFrameTypeSkip) { | |
for (int li = 0; li < info.iLayerNum; ++li) { | |
const auto& l = info.sLayerInfo[li]; | |
uint8_t* buf = l.pBsBuf; | |
for (int ni = 0; ni < l.iNalCount; ++ni) { | |
mp4_h26x_write_nal(&writer, buf, l.pNalLengthInByte[ni], 90000/fps); | |
buf += l.pNalLengthInByte[ni]; | |
} | |
fwrite(l.pBsBuf, 1, buf-l.pBsBuf, fraw); | |
} | |
} | |
} | |
// teardown | |
enc->Uninitialize(); | |
WelsDestroySVCEncoder(enc); | |
MP4E_close(mux); | |
mp4_h26x_write_close(&writer); | |
fclose(fout); | |
fclose(fraw); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment