Skip to content

Instantly share code, notes, and snippets.

@falsycat
Created June 29, 2022 08:56
Show Gist options
  • Save falsycat/5ded0a92625b6f38c7f871dddb638158 to your computer and use it in GitHub Desktop.
Save falsycat/5ded0a92625b6f38c7f871dddb638158 to your computer and use it in GitHub Desktop.
create mp4 video using minimp4.h + openh264
#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