diff --git a/CMakeLists.txt b/CMakeLists.txt index dd9d6d8..d8dbe68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,32 +7,19 @@ project( LANGUAGES CXX) find_package(spdlog REQUIRED) -find_package(PkgConfig REQUIRED) -pkg_check_modules(FFMPEG REQUIRED IMPORTED_TARGET - libavcodec - libavformat - libavutil -) - find_package(avcpp REQUIRED) # ############################################################################## -add_executable(mosh-me-2 - ${PROJECT_SOURCE_DIR}/app/mosh-me-2.cpp +add_executable(mosh-me + ${PROJECT_SOURCE_DIR}/app/mosh-me.cpp ) -target_link_libraries(mosh-me-2 avcpp::avcpp spdlog::spdlog) -target_compile_features(mosh-me-2 PUBLIC cxx_std_23) -target_include_directories(mosh-me-2 PRIVATE ${PROJECT_SOURCE_DIR}/include) - -add_executable(mosh-me ${PROJECT_SOURCE_DIR}/app/mosh-me.cpp) - -target_link_libraries(mosh-me PkgConfig::FFMPEG spdlog::spdlog) +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) -install(TARGETS mosh-me mosh-me-2) +install(TARGETS mosh-me mosh-me) ################################################################################ diff --git a/app/mosh-me-2.cpp b/app/mosh-me-2.cpp deleted file mode 100644 index 891c911..0000000 --- a/app/mosh-me-2.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) { - - if (argc < 4) { - spdlog::error("Usage: {} ", - argv[0]); - return 1; - } - - const char *input_file = argv[1]; - const char *output_file = argv[2]; - int smear_frames = atoi(argv[3]); - - av::init(); - - av::FormatContext ictx; - av::FormatContext octx; - ictx.openInput(input_file); - ictx.findStreamInfo(); - - std::vector stream_map(ictx.streamsCount()); - - off_t oix = 0; - for (size_t i = 0; i < stream_map.size(); i++) { - auto istream = ictx.stream(i); - - if (istream.codecParameters().codecType() != AVMEDIA_TYPE_AUDIO || - istream.codecParameters().codecType() != AVMEDIA_TYPE_VIDEO || - istream.codecParameters().codecType() != AVMEDIA_TYPE_SUBTITLE) { - stream_map[i] = -1; - } - - auto ostream = octx.addStream(); - ostream.setCodecParameters(istream.codecParameters()); - ostream.codecParameters().codecTag(0); - stream_map[i] = oix++; - } - - octx.openOutput(output_file); - octx.writeHeader(); - - av::Packet packet_buffer; - - for (;;) { - auto pkt = ictx.readPacket(); - - if (pkt.isNull()) { - break; - } - - auto istream = ictx.stream(pkt.streamIndex()); - - if (pkt.streamIndex() >= stream_map.size() || - stream_map[pkt.streamIndex()] < 0 || pkt.isKeyPacket()) { - continue; - } - - pkt.setStreamIndex(stream_map[pkt.streamIndex()]); - - if (auto ts = pkt.pts().timestamp(); ts % smear_frames == 0) { - packet_buffer = pkt; - } else { - auto dts = pkt.dts(); - auto pts = pkt.pts(); - auto dur = pkt.duration(); - pkt = packet_buffer; - pkt.setDts(dts); - pkt.setPts(pts); - pkt.setDuration(dur); - } - - octx.writePacket(pkt); - } - - octx.writeTrailer(); -} diff --git a/app/mosh-me.cpp b/app/mosh-me.cpp index 45cc3b6..891c911 100644 --- a/app/mosh-me.cpp +++ b/app/mosh-me.cpp @@ -1,152 +1,82 @@ -extern "C" { -#include -#include -} - +#include +#include +#include +#include #include +#include -static void log_err(int err) { - char buf[256]; - av_strerror(err, buf, sizeof(buf)); - spdlog::error("FFMPEG error: {}", buf); -} +int main(int argc, char *argv[]) { -static void smearStreams(const std::vector &stream_list, - AVFormatContext *input_format, - AVFormatContext *output_format) { + if (argc < 4) { + spdlog::error("Usage: {} ", + argv[0]); + return 1; + } - bool remove_iframes = false; + const char *input_file = argv[1]; + const char *output_file = argv[2]; + int smear_frames = atoi(argv[3]); + + av::init(); + + av::FormatContext ictx; + av::FormatContext octx; + ictx.openInput(input_file); + ictx.findStreamInfo(); + + std::vector stream_map(ictx.streamsCount()); + + off_t oix = 0; + for (size_t i = 0; i < stream_map.size(); i++) { + auto istream = ictx.stream(i); + + if (istream.codecParameters().codecType() != AVMEDIA_TYPE_AUDIO || + istream.codecParameters().codecType() != AVMEDIA_TYPE_VIDEO || + istream.codecParameters().codecType() != AVMEDIA_TYPE_SUBTITLE) { + stream_map[i] = -1; + } + + auto ostream = octx.addStream(); + ostream.setCodecParameters(istream.codecParameters()); + ostream.codecParameters().codecTag(0); + stream_map[i] = oix++; + } + + octx.openOutput(output_file); + octx.writeHeader(); + + av::Packet packet_buffer; - AVPacket prev; for (;;) { - AVPacket packet; - if (auto ret = av_read_frame(input_format, &packet); ret < 0) { + auto pkt = ictx.readPacket(); + + if (pkt.isNull()) { break; } - AVStream *istream = input_format->streams[packet.stream_index]; - if (packet.stream_index >= input_format->nb_streams || - stream_list[packet.stream_index] < 0 || - (istream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - packet.flags & AV_PKT_FLAG_KEY && remove_iframes)) { - av_packet_unref(&packet); + auto istream = ictx.stream(pkt.streamIndex()); + + if (pkt.streamIndex() >= stream_map.size() || + stream_map[pkt.streamIndex()] < 0 || pkt.isKeyPacket()) { continue; } - // Map to output stream index - packet.stream_index = stream_list[packet.stream_index]; - AVStream *ostream = output_format->streams[packet.stream_index]; + pkt.setStreamIndex(stream_map[pkt.streamIndex()]); - if (packet.pts > 0 && packet.pts % 25 < 10 && packet.pts % 2 == 0) { - prev.pts = packet.pts; - prev.dts = packet.dts; - prev.duration = packet.duration; - packet = prev; + if (auto ts = pkt.pts().timestamp(); ts % smear_frames == 0) { + packet_buffer = pkt; + } else { + auto dts = pkt.dts(); + auto pts = pkt.pts(); + auto dur = pkt.duration(); + pkt = packet_buffer; + pkt.setDts(dts); + pkt.setPts(pts); + pkt.setDuration(dur); } - // Adjust time data for output timebase - packet.pts = - av_rescale_q_rnd(packet.pts, istream->time_base, ostream->time_base, - AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); - packet.dts = - av_rescale_q_rnd(packet.dts, istream->time_base, ostream->time_base, - AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); - packet.duration = - av_rescale_q(packet.duration, istream->time_base, ostream->time_base); - packet.pos = -1; // unknown position - - if (auto ret = av_interleaved_write_frame(output_format, &packet); - ret < 0) { - spdlog::error("Could not mux packet"); - log_err(ret); - } - - prev = packet; - - av_packet_unref(&packet); + octx.writePacket(pkt); } - av_packet_unref(&prev); -} - -static std::vector -prepareOutputStreams(const AVFormatContext *input_format, - AVFormatContext *output_format) { - - std::vector streams_list(input_format->nb_streams); - off_t stream_ix = 0; - - for (off_t i = 0; i < input_format->nb_streams; i++) { - AVStream *istream = input_format->streams[i]; - AVCodecParameters *icpar = istream->codecpar; - if (icpar->codec_type != AVMEDIA_TYPE_AUDIO && - icpar->codec_type != AVMEDIA_TYPE_VIDEO && - icpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { - streams_list[i] = -1; - continue; - } - - streams_list[i] = stream_ix++; - AVStream *ostream = avformat_new_stream(output_format, nullptr); - if (auto ret = avcodec_parameters_copy(ostream->codecpar, icpar); ret < 0) { - spdlog::error("Could not prepare output stream"); - log_err(ret); - } - } - - return streams_list; -} - -int main(int argc, const char *argv[]) { - if (argc < 3) { - spdlog::error("Please invoke with {} ", argv[0]); - return 1; - } - spdlog::info("Opening File {}", argv[1]); - - AVFormatContext *input_format = nullptr; - AVFormatContext *output_format = nullptr; - if (auto ret = avformat_open_input(&input_format, argv[1], nullptr, nullptr); - ret < 0) { - log_err(ret); - return 1; - } - - if (auto ret = avformat_find_stream_info(input_format, nullptr); ret < 0) { - log_err(ret); - } - - spdlog::info("Format: {}, frames: {}, bitrate: {}", - input_format->iformat->name, input_format->duration, - input_format->bit_rate); - - if (auto ret = avformat_alloc_output_context2(&output_format, nullptr, - nullptr, argv[2]); - ret < 0) { - log_err(ret); - } - - auto streams = prepareOutputStreams(input_format, output_format); - - if (!(output_format->oformat->flags & AVFMT_NOFILE)) { - if (auto ret = avio_open(&output_format->pb, argv[2], AVIO_FLAG_WRITE); - ret < 0) { - spdlog::error("Could not open output file {}", argv[2]); - log_err(ret); - } - } - - if (auto ret = avformat_write_header(output_format, nullptr); ret < 0) { - spdlog::error("Could not write header"); - log_err(ret); - } - - smearStreams(streams, input_format, output_format); - - av_write_trailer(output_format); - - avformat_close_input(&input_format); - if (output_format && !(output_format->oformat->flags & AVFMT_NOFILE)) { - avio_closep(&output_format->pb); - } - avformat_free_context(output_format); + + octx.writeTrailer(); } diff --git a/nix/mosh-me.nix b/nix/mosh-me.nix index a90911c..d5976dd 100644 --- a/nix/mosh-me.nix +++ b/nix/mosh-me.nix @@ -5,14 +5,13 @@ spdlog, stdenv, pkg-config, - ffmpeg_7, avcpp, }: stdenv.mkDerivation (finalAttrs: { name = "mosh-me"; src = ../.; nativeBuildInputs = [cmake ninja pkg-config]; - buildInputs = [ffmpeg_7 spdlog avcpp]; + buildInputs = [spdlog avcpp]; cmakeFlags = [ (lib.cmakeBool "BUILD_TESTING" finalAttrs.doCheck) ];