feat: add first smearing functionality
This commit is contained in:
parent
60257c85ea
commit
6f3d503f74
151
app/mosh-me.cpp
151
app/mosh-me.cpp
@ -1,3 +1,152 @@
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/error.h>
|
||||
}
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
int main() { spdlog::info("Hello!!"); }
|
||||
static void log_err(int err) {
|
||||
char buf[256];
|
||||
av_strerror(err, buf, sizeof(buf));
|
||||
spdlog::error("FFMPEG error: {}", buf);
|
||||
}
|
||||
|
||||
static void smearStreams(const std::vector<off_t> &stream_list,
|
||||
AVFormatContext *input_format,
|
||||
AVFormatContext *output_format) {
|
||||
|
||||
bool remove_iframes = false;
|
||||
|
||||
AVPacket prev;
|
||||
for (;;) {
|
||||
AVPacket packet;
|
||||
if (auto ret = av_read_frame(input_format, &packet); ret < 0) {
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Map to output stream index
|
||||
packet.stream_index = stream_list[packet.stream_index];
|
||||
AVStream *ostream = output_format->streams[packet.stream_index];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
av_packet_unref(&prev);
|
||||
}
|
||||
|
||||
static std::vector<off_t>
|
||||
prepareOutputStreams(const AVFormatContext *input_format,
|
||||
AVFormatContext *output_format) {
|
||||
|
||||
std::vector<off_t> 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 {} <input file> <output file>", 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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user