diff --git a/CMakeLists.txt b/CMakeLists.txt index d8dbe68..3c0bef0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,15 @@ target_link_libraries(mosh-me avcpp::avcpp spdlog::spdlog) target_compile_features(mosh-me PUBLIC cxx_std_23) target_include_directories(mosh-me PRIVATE ${PROJECT_SOURCE_DIR}/include) +add_executable(mk-moshable + ${PROJECT_SOURCE_DIR}/app/mk-moshable.cpp +) +target_link_libraries(mk-moshable avcpp::avcpp spdlog::spdlog) +target_compile_features(mk-moshable PUBLIC cxx_std_23) +target_include_directories(mk-moshable PRIVATE ${PROJECT_SOURCE_DIR}/include) -install(TARGETS mosh-me mosh-me) + +install(TARGETS mosh-me mk-moshable) ################################################################################ diff --git a/app/mk-moshable.cpp b/app/mk-moshable.cpp new file mode 100644 index 0000000..da263a1 --- /dev/null +++ b/app/mk-moshable.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + if (argc < 3) { + spdlog::error("Please invoke with {} ", argv[0]); + } + + av::init(); + + try { + + av::FormatContext ictx; + ictx.openInput(argv[1]); + ictx.findStreamInfo(); + + off_t v_istream_ix = -1; + for (off_t i = 0; i < ictx.streamsCount(); i++) { + auto stream = ictx.stream(i); + if (stream.isVideo() && stream.isValid()) { + v_istream_ix = i; + } + } + if (v_istream_ix == -1) { + spdlog::error("No video stream found in {}", argv[1]); + return 1; + } + av::VideoDecoderContext decoder(ictx.stream(v_istream_ix)); + decoder.open(); + + av::FormatContext octx; + av::OutputFormat ofmt; + ofmt.setFormat("", argv[2]); + octx.setFormat(ofmt); + auto ocodec = av::findEncodingCodec("libxvid"); + av::VideoEncoderContext encoder(ocodec); + encoder.setPixelFormat(decoder.pixelFormat()); + encoder.setWidth(decoder.width()); + encoder.setHeight(decoder.height()); + encoder.setGopSize(1000); + encoder.setMaxBFrames(0); + encoder.setGlobalQuality(1); + encoder.raw()->qmin = 1; + encoder.raw()->qmax = 1; + encoder.setFlags(AV_CODEC_FLAG_QPEL | AV_CODEC_FLAG_4MV); + encoder.setTimeBase({1, 1000}); + + encoder.open(); + + auto ostream = octx.addStream(encoder); + ostream.setFrameRate(ictx.stream(v_istream_ix).frameRate()); + + octx.openOutput(argv[2]); + octx.writeHeader(); + + for (;;) { + auto pkt = ictx.readPacket(); + if (pkt.isNull()) { + break; + } + + if (pkt.streamIndex() != v_istream_ix) { + continue; + } + + auto frame = decoder.decode(pkt); + + if (frame) { + frame.setTimeBase(encoder.timeBase()); + frame.setStreamIndex(0); + frame.setPictureType(); + + auto opkt = encoder.encode(frame); + if (opkt) { + opkt.setStreamIndex(0); + octx.writePacket(opkt); + } + } + } + + octx.writeTrailer(); + octx.flush(); + } catch (const av::Exception &e) { + spdlog::error("{}", e.what()); + } +}